1 R语言高效数据清理包dplyr学习

xueqin.tv

1.1 Chapter0 dplyr介绍

dplyr是一款用于数据整理的R包,本节内容介绍了dplyr的特性以及雪晴数据网《dplyr高效数据清理》的基本的内容,感兴趣的同学请尽快报名 {r Load dplyr package} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages('dplyr') require(dplyr) }

1.2 Chapter1 数据导入

介绍如何将文本格式的数据导入到R的内存,主要介绍read.table和read.csv函数,及常用参数的使用

1.2.1 read.table

read.table( ## file path file, ## 1st line as header/column name header = FALSE, ## separator strings sep = “”, ## how manhy rows need read nrows = -1, ## how manuy rows need skip skip = 0, ## not available data define as NA fill = !blank.lines.skip)

```{r read.table instruction} #example read.table(file = “dplyr-data/read.table/file1.txt”) # V1 V2 V3 # 1 name age height # 2 John 10 150 # 3 Jack 27 180 # 4 Mary 29 167

read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167

file1.data <- read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE) file1.data

2 sep parameter

read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE, sep = " “) # name.age.height # 1 John10150 # 2 Jack27180 # 3 Mary29167

3 tab and new row

cat(“1”) # 1 cat(“1”) # # # 1

read.table(file = “dplyr-data/read.table/file1.txt”, header = TRUE, sep = “”) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167

4 sep is a comma

read.table(file = “dplyr-data/read.table/file2.txt”, header = TRUE, sep = “,”) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167

5 skip & fill parameter

read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE) # Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : # line 4 did not have 3 elements

read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, nrows = 4) # Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : # line 4 did not have 3 elements

read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, nrows = 3) # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167 # but we missing 1 row, so skip parameter is used as follow

read.table(file = “dplyr-data/read.table/file3.txt”, header = FALSE, skip = 5) # V1 V2 V3 # 1 Steven 45 175 # skip 1st 5 rows and no header

read.table(file = “dplyr-data/read.table/file3.txt”, header = TRUE, fill = T) # fill missing values as NA # name age height # 1 John 10 150 # 2 Jack 27 180 # 3 Mary 29 167 # 4 DDD NA NA # 5 Steven 45 175

```

5.0.1 read.csv

{r import order data by read.csv} # import data and change to tbl object order <- read.csv("dplyr-data/order.csv") head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)

5.1 Chapter2 tbl对象的介绍

本节内容介绍如果用data.frame对象构造成tbl对象 tbl是dplyr定义的数据类型,可以接受data.frame,cube,sql ```{r import data by read.table} # import data order <- read.table(file = “dplyr-data/order.csv”, header = T, sep = “,”) class(order) # [1] “data.frame” head(order) tail(order)

6 Load dplyr package

if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) } # change to tbl use tbl_df function order_tbl <- tbl_df(order) class(order_tbl) # [1] “tbl_df” “tbl” “data.frame” order_tbl

7 for a data.frame, is not nessary to change to tbl object

8 for sql object, can useful to use dplyr to manupulate data

9 another way to read data

library(readr) order <- read_csv(“E:/03-Download/dplyr/dplyr-data/order.csv”) View(order) ```

9.1 Chapter3 数据筛选–filter函数

filter(tbl/data.fram, condition) and output a data.frame, filter rows/observation ```{r filter in dplyr} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

df <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df) tbl # # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5

10 filter a value that match some condition

filter(tbl, color == “blue”) # # A tibble: 3 × 2 # color value # # 1 blue 1 # 2 blue 3 # 3 blue 4

11 filter value in 1 or 4

filter(tbl, value %in% c(1,4)) # A tibble: 2 × 2 # color value # # 1 blue 1 # 2 blue 4

12 import data and change to tbl object

order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)

13 filter order data is 2009-10-13 rows

filter(order_tbl, orderdate == “2009-10-13”)

14 filter order data is 2009-10-13 rows and total price greater than 100 rows, 1 row match and assign to filterData

filterData <- filter(order_tbl, orderdate == “2009-10-13” & totalprice > 100) View(filterData) ```

14.1 Chapter4 子集选取函数–select

select columns/variable by name/match rules ```{r select function in dplyr} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

df <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df) tbl

15 just select color column

select(tbl, color) # A tibble: 5 × 1 # color # # 1 blue # 2 black # 3 blue # 4 blue # 5 black

16 select all other columns except color column equals select value column

select(tbl, -color) # A tibble: 5 × 1 # value # # 1 1 # 2 2 # 3 3 # 4 4 # 5 5 ```

Useful function to select ```{r Useful function to select} starts_with(x, ignore.case = TRUE) # column/variable start with chart x ends_with(x, ignore.case = TRUE) # column/variable end with chart x contains(x, ignore.case = TRUE) # column/variable contains chart x matches(x, ignore.case = TRUE) # column/variable matches regular expression x num_range(“x”, 1:5, width = 2) # column/variable from x01 to x05 one_of(“x”, “y”, “z”) # column/variable contains in x, y, z everything() # all column/variable

17 e.g. order_tbl, check column

names(order_tbl) # [1] “X” “orderid” “customerid” “campaignid” # [5] “orderdate” “city” “state” “zipcode” # [9] “paymenttype” “totalprice” “numorderlines” “numunits”

18 select order data and total price

date_price <- select(order_tbl,orderdate, totalprice) date_price

19 rename column name at the same time

date_price2 <- select(order_tbl,date = orderdate, price = totalprice) date_price2

20 select starts with order column name

Start_With_Order <- select(order_tbl,starts_with(“order”,ignore.case = TRUE)) Start_With_Order # A tibble: 100,000 × 2 # orderid orderdate # # 1 1002854 2009-10-13 # 2 1002855 2009-10-13 # 3 1002856 2011-06-02 # 4 1002857 2009-10-14 # 5 1002886 2010-11-19 # 6 1002887 2009-10-15 # 7 1002888 2009-10-15 # 8 1002889 2009-10-15 # 9 1002890 2009-10-15 # 10 1003004 2009-10-15 # … with 99,990 more rows

21 select contains id column name

Contains_ID <- select(order_tbl, contains(“id”,ignore.case = TRUE)) head(Contains_ID,5) # A tibble: 5 × 3 # orderid customerid campaignid # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141

22 rename function

as.data.frame(Contains_ID) # rename the new name must at the left after_rename <- rename(Contains_ID, ooID = orderid, ooID = customerid, ooCAID = campaignid) head(Contains_ID,5) # A tibble: 5 × 3 # orderid customerid campaignid # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141

23 after rename returns a new tbl, the origin Contains_ID will not be changed

head(after_rename,5) # A tibble: 5 × 3 # ooID ooID ooCAID # # 1 1002854 45978 2141 # 2 1002855 125381 2173 # 3 1002856 103122 2141 # 4 1002857 130980 2173 # 5 1002886 48553 2141 # this works in the code below head(rename(iris, pt = Petal.Length),5)

24 e.g. with select from ? rename

iris <- tbl_df(iris) # so it prints a little nicer select(iris, starts_with(“Petal”)) select(iris, ends_with(“Width”)) select(iris, contains(“etal”)) select(iris, matches(“.t.”)) select(iris, Petal.Length, Petal.Width) vars <- c(“Petal.Length”, “Petal.Width”) select(iris, one_of(vars))

df <- as.data.frame(matrix(runif(100), nrow = 10)) df <- tbl_df(df[c(3, 4, 7, 1, 9, 8, 5, 2, 6, 10)]) select(df, V4:V6) select(df, num_range(“V”, 4:6))

25 Drop variables

select(iris, -starts_with(“Petal”)) select(iris, -ends_with(“Width”)) select(iris, -contains(“etal”)) select(iris, -matches(“.t.”)) select(iris, -Petal.Length, -Petal.Width)

26 Rename variables:

27 * select() keeps only the variables you specify

select(iris, petal_length = Petal.Length) # Renaming multiple variables uses a prefix: select(iris, petal = starts_with(“Petal”))

28 Reorder variables: keep the variable “Species” in the front

select(iris, Species, everything())

29 * rename() keeps all variables

rename(iris, petal_length = Petal.Length)

30 Programming with select —————————————————

select_(iris, ~Petal.Length) select_(iris, “Petal.Length”) select_(iris, lazyeval::interp(~matches(x), x = “.t.”)) select_(iris, quote(-Petal.Length), quote(-Petal.Width)) select_(iris, .dots = list(quote(-Petal.Length), quote(-Petal.Width))) ```

30.1 Chapter5 数据的排序–arrange函数

traditional method: order function ```{r use order to order} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df1) tbl # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5

31 order use index

df_order <- order(df1$color) df_order # [1] 2 5 1 3 4 df1[df_order,] # color value # 2 black 2 # 5 black 5 # 1 blue 1 # 3 blue 3 # 4 blue 4

32 use arrange to order a data frame/tbl, default is aesc, 1 to 3

arrange(df1, color) # use desc to order by 3 to 1 arrange(df1, desc(color))

33 import data and change to tbl object

order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5)

34 order by date

tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) arrange(tbl, odate) # A tibble: 100,000 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70 # 6 2009-10-04 50 # 7 2009-10-04 50 # 8 2009-10-04 40 # 9 2009-10-04 40 # 10 2009-10-04 40 # … with 99,990 more rows

35 order by date & by price desc 3 to 1

arrange(tbl, odate, desc(oprice)) # A tibble: 100,000 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70 # 6 2009-10-04 50 # 7 2009-10-04 50 # 8 2009-10-04 40 # 9 2009-10-04 40 # 10 2009-10-04 40 # … with 99,990 more rows ```

35.1 Chapter6 数据扩展–mutate函数

数据扩展,保留原来的变量、列的基础上增加变量或者列 ```{r mutate function} # Load dplyr package in a safer way if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl <- tbl_df(df1) tbl # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5

36 add double column

mutate(tbl, double = 2 * value) # A tibble: 5 × 3 # color value double # # 1 blue 1 2 # 2 black 2 4 # 3 blue 3 6 # 4 blue 4 8 # 5 black 5 10

37 add double column and quadruple column

mutate(tbl, double = 2 * value, quadruple = 4 * value) # A tibble: 5 × 4 # color value double quadruple # # 1 blue 1 2 4 # 2 black 2 4 8 # 3 blue 3 6 12 # 4 blue 4 8 16 # 5 black 5 10 20

38 use order data set to mutate year, month and date

39 import data and change to tbl object

order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5) tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) tbl <- arrange(tbl, odate, desc(oprice)) head(tbl, 5) # # A tibble: 5 × 2 # odate oprice # # 1 2009-10-04 200 # 2 2009-10-04 120 # 3 2009-10-04 100 # 4 2009-10-04 100 # 5 2009-10-04 70

40 mutate

tbl_New <- mutate(tbl, oYear = substr(odate, 1, 4), oMonth = substr(odate, 6, 7),oDate = substr(odate, 9, 10)) head(tbl_New,5) # A tibble: 5 × 5 # odate oprice oYear oMonth oDate # # 1 2009-10-04 200 2009 10 04 # 2 2009-10-04 120 2009 10 04 # 3 2009-10-04 100 2009 10 04 # 4 2009-10-04 100 2009 10 04 # 5 2009-10-04 70 2009 10 04

41 transmute

42 Mutate adds new variables and preserves existing;

43 transmute drops existing variables.

df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl_transmute <- tbl_df(df1) tbl_transmute # A tibble: 5 × 2 # color value # # 1 blue 1 # 2 black 2 # 3 blue 3 # 4 blue 4 # 5 black 5

transmute(tbl_transmute, double = 2 * value, quadruple = 4 * value) # A tibble: 5 × 2 # double quadruple # # 1 2 4 # 2 4 8 # 3 6 12 # 4 8 16 # 5 10 20 ```

43.1 Chapter7 数据汇总–summarise函数

数据汇总-将多个值汇总为一个数据值 ```{r summarise} df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) tbl_summarise <- tbl_df(df1)

summarise(tbl_summarise, total = sum(value)) # A tibble: 1 × 1 # total # # 1 15

44 multi parameter

summarise(tbl_summarise, total_value = sum(value), mean_value = mean(value), sd_value = sd(value)) # A tibble: 1 × 3 # total_value mean_value sd_value # # 1 15 3 1.581139

45 use order data set to summarise

46 import data and change to tbl object

order <- read.csv(“dplyr-data/order.csv”) head(order,5) order_tbl <- tbl_df(order) head(order_tbl, 5) tbl <- select(order_tbl, odate = orderdate, oprice = totalprice) # tbl <- arrange(tbl, odate, desc(oprice)) summarise(tbl, max = max(oprice), min = min(oprice), mean = mean(oprice)) # A tibble: 1 × 3 # max min mean # # 1 6780 0 60.77773

``` summarise()中的汇总函数将一列值转换为一个单独的值输出 R自带的统计函数都是可以使用的 min(), max(), mean(), sum(), sd(), median(), IQR()

此外,dplyr还提供了一些其他会用到的函数 n():观测值的个数 n_distinct(x):不相同的观测值的个数 first(x),last(x)和nth(x, n)获取第一个,最后一个,和第n个数据

{r first and last value} summarise(tbl, first = first(odate), last = last(odate)) # A tibble: 1 × 2 # first last # <fctr> <fctr> # 1 2009-10-13 2014-04-28

46.1 Chapter8 数据连接–join函数

dplyr advanced function: - data set join/connection, like excel vlookup function - group_by - pipe function: %>% - other function: do, plyr::colwise - mysql database connection

```{r join} x <- data.frame(name = c(“John”, “Paul”, “George”, “Ringo”, “Stuart”, “Siqin”), instrument = c(“guitar”, “bass”, “guitar”, “drums”, “bass”, “drums”)) x # name instrument # 1 John guitar # 2 Paul bass # 3 George guitar # 4 Ringo drums # 5 Stuart bass # 6 Siqin drums y <- data.frame(name = c(“John”, “Paul”, “George”, “Ringo”, “Brian”), band = c(T, T, T, T, T)) y # name band # 1 John TRUE # 2 Paul TRUE # 3 George TRUE # 4 Ringo TRUE # 5 Brian TRUE

47 left_join like excel vlookup, all value in left table will remain, but not match value in right table will be set NA

left_join(x, y, by = “name”) # name instrument band # 1 John guitar TRUE # 2 Paul bass TRUE # 3 George guitar TRUE # 4 Ringo drums TRUE # 5 Stuart bass NA # 6 Siqin drums NA

48 inner_join, just remain left and right table match value,

49 and add column(right table data) in left table

50 and not match value in left table will be discarded

inner_join(x, y, by = “name”) # name instrument band # 1 John guitar TRUE # 2 Paul bass TRUE # 3 George guitar TRUE # 4 Ringo drums TRUE

51 semi_join, just remain left table that matches the value in right table, and right table value will not used

semi_join(x, y, by = “name”) # name instrument # 1 John guitar # 2 Paul bass # 3 George guitar # 4 Ringo drums

52 anti_join, just convert with semi_join, just keep match values in right table

anti_join(x, y, by = “name”) # name instrument # 1 Siqin drums # 2 Stuart bass

53 use order and custimer data set to join

54 import data and change to tbl object

df_order <- read.csv(“dplyr-data/order.csv”) df_customer <- read.csv(“dplyr-data/customer.csv”) head(df_order,5) head(df_customer,5)

tbl_order <- tbl_df(df_order) tbl_customer <- tbl_df(df_customer)

s_order <- select(tbl_order, odate = orderdate, ocust_id = customerid) s_customer <- select(tbl_customer, ocust_id = customerid, gender, firstname,lastname =Lastname)

arrange(left_join(s_order, s_customer, by = “ocust_id”), firstname) ```

54.1 Chapter9 分类汇总 – group_by

分类汇总 – group_by ```{r group_by function} #summary by year–Group-wise summary # group_by()转变成一 个分好组的数据框

df1 <- data.frame( color = c(“blue”, “black”, “blue”, “blue”, “black”), value = 1:5 ) summarise(df1, total =sum(value)) # just get one sumarised data total # total # 1 15

55 group by color

by_color <- group_by(df1, color) # then summarise by group summarise(by_color, total = sum(value)) # A tibble: 2 × 2 # color total # # 1 black 7 # 2 blue 8

56 use order data set

57 import data and change to tbl object

df_order <- read.csv(“dplyr-data/order.csv”) head(df_order,5)

tbl_order <- tbl_df(df_order) # tbl_customer <- tbl_df(df_customer)

s_order <- select(tbl_order, odate = orderdate, oprice = totalprice)

58 mutate year and month column

m_order <- mutate(s_order, oyear = substr(odate, 1, 4), omonth = substr(odate, 6, 7)) head(m_order, 5)

59 group by year

m_order_year <- group_by(m_order, oyear) head(m_order_year) # Source: local data frame [6 x 4] # Groups: oyear [3] # # odate oprice oyear omonth # # 1 2009-10-13 190.00 2009 10 # 2 2009-10-13 10.00 2009 10 # 3 2011-06-02 35.22 2011 06 # 4 2009-10-14 10.00 2009 10 # 5 2010-11-19 10.00 2010 11 # 6 2009-10-15 10.00 2009 10

60 summary yearly price and average price, and max month for check data period(year 2014 just have 5 month)

61 summarise support multi parameter

summarise(m_order_year, yearly_price = sum(oprice), average_price = mean(oprice), Max_Month = max(omonth)) # A tibble: 6 × 4 # oyear yearly_price average_price max(omonth) # # 1 2009 262627.5 34.13850 12 # 2 2010 967429.2 52.23982 12 # 3 2011 1380636.6 51.35342 12 # 4 2012 1404113.1 68.40990 12 # 5 2013 1633004.8 76.71011 12 # 6 2014 429962.0 84.47190 05 ```

61.1 Chapter10 管道函数

%>% or %.% use the previous function(left)’s out put as the next function(right)’s input. ```{r pipe function} 1:5 %>% mean() # [1] 3 1:5 %>% mean(.) %>% sqrt() # [1] 1.732051

62 use order data set

63 01. import data and change to tbl object

df_order <- read.csv(“dplyr-data/order.csv”) head(df_order,5) # 02. change to tbl object tbl_order <- tbl_df(df_order) head(tbl_order, 5)

64 03. mutate year and month column

m_order <- mutate(tbl_order, oyear = substr(orderdate, 1, 4), omonth = substr(orderdate, 6, 7)) head(m_order, 5)

65 04. group by month

m_order_month <- group_by(m_order,omonth)

66 05. summarise order count by month

summarise(m_order_month, monthly_order_count = n())

67 use pipe function rewrite above flow 03,04,05

tbl_order %>% mutate(oyear = substr(orderdate, 1, 4), omonth = substr(orderdate, 6, 7)) %>% group_by(omonth) %>% summarise(monthly_order_count = n()) # A tibble: 12 × 2 # omonth monthly_order_count # # 1 01 13601 # 2 02 6609 # 3 03 6235 # 4 04 6042 # 5 05 5037 # 6 06 4691 # 7 07 4354 # 8 08 4763 # 9 09 5676 # 10 10 7106 # 11 11 17268 # 12 12 18618

```

67.1 Chapter11 colwise和do函数

筛选销售额每年最大的记录 ```{r colwise and do function} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

68 import data

order <- read.csv(“dplyr-data/order.csv”)

69 Get Yearly Order data and split by year

Yearly_Order <- order %>% select(orderdate, totalprice) %>% mutate(oyear = substr(orderdate, 1, 4))

70 Group by Year, Get Yealy Maximun Order

Yealy_Maximun <- Yearly_Order %>% group_by(oyear) %>% summarise(max(totalprice))

```

筛选每年销售额最大的两条记录 ```{r do(data, fun(.))} # Load dplyr package if(!suppressWarnings(require(dplyr))) { install.packages(‘dplyr’) require(dplyr) }

71 import data

order <- read.csv(“dplyr-data/order.csv”)

72 Get Yearly Order data and split by year

Yearly_Order <- order %>% select(orderdate, totalprice) %>% mutate(oyear = substr(orderdate, 1, 4))

73 Group by Year, Get Yealy Max 2 Orders

Yearly_Order %>% group_by(oyear) %>% arrange(desc(totalprice)) %>% do(., head(., 2)) # Source: local data frame [12 x 3] # Groups: oyear [6] # # orderdate totalprice oyear # # 1 2009-12-17 2244.00 2009 # 2 2009-10-26 1154.65 2009 # 3 2010-09-05 2250.00 2010 # 4 2010-10-06 2250.00 2010 # 5 2011-05-09 2250.00 2011 # 6 2011-05-17 2000.00 2011 # 7 2012-12-12 6780.00 2012 # 8 2012-11-12 6606.00 2012 # 9 2013-01-18 4050.00 2013 # 10 2013-06-26 3592.00 2013 # 11 2014-03-29 4735.00 2014 # 12 2014-03-30 4378.50 2014

```

73.0.1 plyr package colwise function

```{r colwise function} # Load plyr package if(!suppressWarnings(require(plyr))) { install.packages(‘plyr’) require(plyr) }

74 load and check iris data set

head(iris, 5)

75 to round every column use colwise function

76 call function to each column

77 colwise(function)(data.frame)

colwise(round)(iris[, 1:4]) %>% head(., 5) # Sepal.Length Sepal.Width Petal.Length Petal.Width # 1 5 4 1 0 # 2 5 3 1 0 # 3 5 3 1 0 # 4 5 3 2 0 # 5 5 4 1 0

```

77.1 Chapter12 连接MySQL数据库

连接MySQL数据库 ```{r connect mysql} # mysql data base src_database <- src_mysql(dbname = “sqlbook”, host = “127.0.0.1”, port = “3063”,user = “root”,password = “root”)

78 mysql table

src_table <- tbl(src_database, from = “orders”)

79 execute sql command

sqlQueryResults <- select(src_table, orderid, orderdate) # or use pipe function sqlQueryResults <- src_table %>% select(orderid, orderdate)

80 check sql query command

sqlQueryResults$query

81 save results as csv file

write.csv(sqlQueryResults, “dplyr-data/order_record.csv”)

82 show sqlQueryResults

sqlQueryResults

83 mysql data base

84 mysql -u root -p

85 enter password

86 show databases

87 show databases

88 use which database, change to your database

89 use mydatabase

90 show tables in your database

91 show tables

```

91.1 Chapter13 Example dplyr and pipeline operator

dplyr Examples with pipeline

rlist Examples with pipeline

hflights is a dataset contains information about flights that departed Houston in 2011. In the description the author writes:

This dataset contains all flights departing from Houston airports IAH (George Bush Intercontinental) and HOU (Houston Hobby). The data comes from the Research and Innovation Technology Administration at the Bureau of Transporation statistics: http://www.transtats.bts.gov/DatabaseInfo.asp?DB_ID=120&Link=0

Having known what the data is all about, then we load the libraries and take a look at the structure of the data.

install.packages(c("dplyr","hflights"))
library(dplyr)
library(pipeR)
# or use
library(magrittr)
library(hflights) # install.packages("hflights")
data(hflights)

str(hflights)
# 'data.frame': 227496 obs. of  21 variables:
#  $ Year             : int  2011 2011 2011 2011 2011 2011 2011 2011 2011 2011 ...
#  $ Month            : int  1 1 1 1 1 1 1 1 1 1 ...
#  $ DayofMonth       : int  1 2 3 4 5 6 7 8 9 10 ...
#  $ DayOfWeek        : int  6 7 1 2 3 4 5 6 7 1 ...
#  $ DepTime          : int  1400 1401 1352 1403 1405 1359 1359 1355 1443 1443 ...
#  $ ArrTime          : int  1500 1501 1502 1513 1507 1503 1509 1454 1554 1553 ...
#  $ UniqueCarrier    : chr  "AA" "AA" "AA" "AA" ...
#  $ FlightNum        : int  428 428 428 428 428 428 428 428 428 428 ...
#  $ TailNum          : chr  "N576AA" "N557AA" "N541AA" "N403AA" ...
#  $ ActualElapsedTime: int  60 60 70 70 62 64 70 59 71 70 ...
#  $ AirTime          : int  40 45 48 39 44 45 43 40 41 45 ...
#  $ ArrDelay         : int  -10 -9 -8 3 -3 -7 -1 -16 44 43 ...
#  $ DepDelay         : int  0 1 -8 3 5 -1 -1 -5 43 43 ...
#  $ Origin           : chr  "IAH" "IAH" "IAH" "IAH" ...
#  $ Dest             : chr  "DFW" "DFW" "DFW" "DFW" ...
#  $ Distance         : int  224 224 224 224 224 224 224 224 224 224 ...
#  $ TaxiIn           : int  7 6 5 9 9 6 12 7 8 6 ...
#  $ TaxiOut          : int  13 9 17 22 9 13 15 12 22 19 ...
#  $ Cancelled        : int  0 0 0 0 0 0 0 0 0 0 ...
#  $ CancellationCode : chr  "" "" "" "" ...
#  $ Diverted         : int  0 0 0 0 0 0 0 0 0 0 ...

The data is tabular and very well fit in a data frame. Remarkably it has 227496 rows which is much larger than small datasets like mtcars.

Two columns in the data frame attracts our attention: Distance and ActualElapsedTime. If we divide Distance by ActualElapsedTime we can get the actual flight speed. Therefore, in this example, we use dplyr functions to transform the data in pipeline and see which carrier has faster flights.

hflights %>% 
  # 1. filter out no canceld flight
  filter(Cancelled == 0) %>%
  # 2. mutate new column speed
  mutate(speed = Distance / ActualElapsedTime) %>%
  # 3. save to hflights2
  (~ hflights2) %>% 
  # 4. group_by UniqueCarrier
    group_by(UniqueCarrier) %>%
    #group_by(.data = .,UniqueCarrier)  %>%
  # 5. summarize
  summarize(mean_speed = mean(speed,na.rm = TRUE)) %>%
  # 6. arrange, by speed desc
  arrange(desc(mean_speed)) %>%
  # 7. barplot, why with?
  with(barplot(mean_speed,names.arg = UniqueCarrier,
    main = "Average flight speed"))

91.2 End 2017-06-10 By Stone.Hou

Updated in 20170702, add example

LS0tDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KLS0tDQoNCiMgUuivreiogOmrmOaViOaVsOaNrua4heeQhuWMhWRwbHly5a2m5LmgDQo+IFt4dWVxaW4udHZdKGh0dHA6Ly93d3cueHVlcWluZy50di9sZXNzb24vODMpDQoNCiMjIENoYXB0ZXIwIGRwbHly5LuL57uNDQpkcGx5cuaYr+S4gOasvueUqOS6juaVsOaNruaVtOeQhueahFLljIXvvIzmnKzoioLlhoXlrrnku4vnu43kuoZkcGx5cueahOeJueaAp+S7peWPiumbquaZtOaVsOaNrue9keOAimRwbHly6auY5pWI5pWw5o2u5riF55CG44CL55qE5Z+65pys55qE5YaF5a6577yM5oSf5YW06Laj55qE5ZCM5a2m6K+35bC95b+r5oql5ZCNDQpgYGB7ciBMb2FkIGRwbHlyIHBhY2thZ2V9DQojIExvYWQgZHBseXIgcGFja2FnZQ0KaWYoIXN1cHByZXNzV2FybmluZ3MocmVxdWlyZShkcGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ2RwbHlyJykNCiAgICByZXF1aXJlKGRwbHlyKQ0KfQ0KYGBgDQoNCg0KIyMgQ2hhcHRlcjEg5pWw5o2u5a+85YWlDQrku4vnu43lpoLkvZXlsIbmlofmnKzmoLzlvI/nmoTmlbDmja7lr7zlhaXliLBS55qE5YaF5a2Y77yM5Li76KaB5LuL57uNcmVhZC50YWJsZeWSjHJlYWQuY3N25Ye95pWw77yM5Y+K5bi455So5Y+C5pWw55qE5L2/55SoDQoNCiMjIyByZWFkLnRhYmxlDQoNCnJlYWQudGFibGUoDQogICAgIyMgZmlsZSBwYXRoDQogICAgZmlsZSwNCiAgICAjIyAxc3QgbGluZSBhcyBoZWFkZXIvY29sdW1uIG5hbWUNCiAgICBoZWFkZXIgPSBGQUxTRSwNCiAgICAjIyBzZXBhcmF0b3Igc3RyaW5ncw0KICAgIHNlcCA9ICIiLA0KICAgICMjIGhvdyBtYW5oeSByb3dzIG5lZWQgcmVhZA0KICAgIG5yb3dzID0gLTEsDQogICAgIyMgaG93IG1hbnV5IHJvd3MgbmVlZCBza2lwDQogICAgc2tpcCA9IDAsDQogICAgIyMgbm90IGF2YWlsYWJsZSBkYXRhIGRlZmluZSBhcyBOQQ0KICAgIGZpbGwgPSAhYmxhbmsubGluZXMuc2tpcCkNCg0KYGBge3IgcmVhZC50YWJsZSBpbnN0cnVjdGlvbn0NCiNleGFtcGxlDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUxLnR4dCIpDQojICAgICBWMSAgVjIgICAgIFYzDQojIDEgbmFtZSBhZ2UgaGVpZ2h0DQojIDIgSm9obiAgMTAgICAgMTUwDQojIDMgSmFjayAgMjcgICAgMTgwDQojIDQgTWFyeSAgMjkgICAgMTY3DQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KIyAgIG5hbWUgYWdlIGhlaWdodA0KIyAxIEpvaG4gIDEwICAgIDE1MA0KIyAyIEphY2sgIDI3ICAgIDE4MA0KIyAzIE1hcnkgIDI5ICAgIDE2Nw0KDQpmaWxlMS5kYXRhIDwtIHJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KZmlsZTEuZGF0YQ0KDQojIHNlcCBwYXJhbWV0ZXINCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICIgIikNCiMgICBuYW1lLmFnZS5oZWlnaHQNCiMgMSAgIEpvaG5cdDEwXHQxNTANCiMgMiAgIEphY2tcdDI3XHQxODANCiMgMyAgIE1hcnlcdDI5XHQxNjcNCg0KIyB0YWIgYW5kIG5ldyByb3cNCmNhdCgiXHRcdFx0MSIpDQoJCQkjIDENCmNhdCgiXG5cblx0MSIpDQojDQojDQojIAkxDQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTEudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICJcdCIpDQojICAgbmFtZSBhZ2UgaGVpZ2h0DQojIDEgSm9obiAgMTAgICAgMTUwDQojIDIgSmFjayAgMjcgICAgMTgwDQojIDMgTWFyeSAgMjkgICAgMTY3DQoNCiMgc2VwIGlzIGEgY29tbWENCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTIudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHNlcCA9ICIsIikNCiMgICBuYW1lIGFnZSBoZWlnaHQNCiMgMSBKb2huICAxMCAgICAxNTANCiMgMiBKYWNrICAyNyAgICAxODANCiMgMyBNYXJ5ICAyOSAgICAxNjcNCg0KIyBza2lwICYgZmlsbCBwYXJhbWV0ZXINCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTMudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFKQ0KIyBFcnJvciBpbiBzY2FuKGZpbGUgPSBmaWxlLCB3aGF0ID0gd2hhdCwgc2VwID0gc2VwLCBxdW90ZSA9IHF1b3RlLCBkZWMgPSBkZWMsICA6DQojICAgbGluZSA0IGRpZCBub3QgaGF2ZSAzIGVsZW1lbnRzDQoNCnJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL3JlYWQudGFibGUvZmlsZTMudHh0IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIG5yb3dzID0gNCkNCiMgRXJyb3IgaW4gc2NhbihmaWxlID0gZmlsZSwgd2hhdCA9IHdoYXQsIHNlcCA9IHNlcCwgcXVvdGUgPSBxdW90ZSwgZGVjID0gZGVjLCAgOg0KIyAgIGxpbmUgNCBkaWQgbm90IGhhdmUgMyBlbGVtZW50cw0KDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUzLnR4dCIsDQogICAgaGVhZGVyID0gVFJVRSwNCiAgICBucm93cyA9IDMpDQojICAgbmFtZSBhZ2UgaGVpZ2h0DQojIDEgSm9obiAgMTAgICAgMTUwDQojIDIgSmFjayAgMjcgICAgMTgwDQojIDMgTWFyeSAgMjkgICAgMTY3DQojIGJ1dCB3ZSBtaXNzaW5nIDEgcm93LCBzbyBza2lwIHBhcmFtZXRlciBpcyB1c2VkIGFzIGZvbGxvdw0KDQpyZWFkLnRhYmxlKGZpbGUgPSAiZHBseXItZGF0YS9yZWFkLnRhYmxlL2ZpbGUzLnR4dCIsDQogICAgaGVhZGVyID0gRkFMU0UsDQogICAgc2tpcCA9IDUpDQojICAgICAgIFYxIFYyICBWMw0KIyAxIFN0ZXZlbiA0NSAxNzUNCiMgc2tpcCAxc3QgNSByb3dzIGFuZCBubyBoZWFkZXINCg0KcmVhZC50YWJsZShmaWxlID0gImRwbHlyLWRhdGEvcmVhZC50YWJsZS9maWxlMy50eHQiLA0KICAgIGhlYWRlciA9IFRSVUUsDQogICAgZmlsbCA9IFQpDQojIGZpbGwgbWlzc2luZyB2YWx1ZXMgYXMgTkENCiMgICAgIG5hbWUgYWdlIGhlaWdodA0KIyAxICAgSm9obiAgMTAgICAgMTUwDQojIDIgICBKYWNrICAyNyAgICAxODANCiMgMyAgIE1hcnkgIDI5ICAgIDE2Nw0KIyA0ICAgIERERCAgTkEgICAgIE5BDQojIDUgU3RldmVuICA0NSAgICAxNzUNCg0KYGBgDQoNCiMjIyByZWFkLmNzdg0KYGBge3IgaW1wb3J0IG9yZGVyIGRhdGEgYnkgcmVhZC5jc3Z9DQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCmBgYA0KDQojIyBDaGFwdGVyMiB0Ymzlr7nosaHnmoTku4vnu40NCuacrOiKguWGheWuueS7i+e7jeWmguaenOeUqGRhdGEuZnJhbWXlr7nosaHmnoTpgKDmiJB0Ymzlr7nosaENCnRibOaYr2RwbHly5a6a5LmJ55qE5pWw5o2u57G75Z6L77yM5Y+v5Lul5o6l5Y+XZGF0YS5mcmFtZSxjdWJlLHNxbA0KYGBge3IgaW1wb3J0IGRhdGEgYnkgcmVhZC50YWJsZX0NCiMgaW1wb3J0IGRhdGENCm9yZGVyIDwtIHJlYWQudGFibGUoZmlsZSA9ICJkcGx5ci1kYXRhL29yZGVyLmNzdiIsDQogICAgaGVhZGVyID0gVCwNCiAgICBzZXAgPSAiLCIpDQpjbGFzcyhvcmRlcikNCiMgWzFdICJkYXRhLmZyYW1lIg0KaGVhZChvcmRlcikNCnRhaWwob3JkZXIpDQoNCiMgTG9hZCBkcGx5ciBwYWNrYWdlDQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQojIGNoYW5nZSB0byB0YmwgdXNlIHRibF9kZiBmdW5jdGlvbg0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmNsYXNzKG9yZGVyX3RibCkNCiMgWzFdICJ0YmxfZGYiICAgICAidGJsIiAgICAgICAgImRhdGEuZnJhbWUiDQpvcmRlcl90YmwNCg0KIyBmb3IgYSBkYXRhLmZyYW1lLCBpcyBub3QgbmVzc2FyeSB0byBjaGFuZ2UgdG8gdGJsIG9iamVjdA0KIyBmb3Igc3FsIG9iamVjdCwgY2FuIHVzZWZ1bCB0byB1c2UgZHBseXIgdG8gbWFudXB1bGF0ZSBkYXRhDQoNCiMgYW5vdGhlciB3YXkgdG8gcmVhZCBkYXRhDQpsaWJyYXJ5KHJlYWRyKQ0Kb3JkZXIgPC0gcmVhZF9jc3YoIkU6LzAzLURvd25sb2FkL2RwbHlyL2RwbHlyLWRhdGEvb3JkZXIuY3N2IikNClZpZXcob3JkZXIpDQpgYGANCg0KIyMgQ2hhcHRlcjMg5pWw5o2u562b6YCJLS1maWx0ZXLlh73mlbANCmZpbHRlcih0YmwvZGF0YS5mcmFtLCBjb25kaXRpb24pIGFuZCBvdXRwdXQgYSBkYXRhLmZyYW1lLCBmaWx0ZXIgcm93cy9vYnNlcnZhdGlvbg0KYGBge3IgZmlsdGVyIGluIGRwbHlyfQ0KIyBMb2FkIGRwbHlyIHBhY2thZ2UgaW4gYSBzYWZlciB3YXkNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUoZHBseXIpKSkNCnsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpDQogICAgcmVxdWlyZShkcGx5cikNCn0NCg0KZGYgPC0gZGF0YS5mcmFtZSgNCiAgY29sb3IgPSBjKCJibHVlIiwgImJsYWNrIiwgImJsdWUiLCAiYmx1ZSIsICJibGFjayIpLA0KICB2YWx1ZSA9IDE6NQ0KKQ0KdGJsIDwtIHRibF9kZihkZikNCnRibA0KIyAjIEEgdGliYmxlOiA1IMOXIDINCiMgICAgY29sb3IgdmFsdWUNCiMgICA8ZmN0cj4gPGludD4NCiMgMSAgIGJsdWUgICAgIDENCiMgMiAgYmxhY2sgICAgIDINCiMgMyAgIGJsdWUgICAgIDMNCiMgNCAgIGJsdWUgICAgIDQNCiMgNSAgYmxhY2sgICAgIDUNCg0KIyBmaWx0ZXIgYSB2YWx1ZSB0aGF0IG1hdGNoIHNvbWUgY29uZGl0aW9uDQpmaWx0ZXIodGJsLCBjb2xvciA9PSAiYmx1ZSIpDQojICMgQSB0aWJibGU6IDMgw5cgMg0KIyAgICBjb2xvciB2YWx1ZQ0KIyAgIDxmY3RyPiA8aW50Pg0KIyAxICAgYmx1ZSAgICAgMQ0KIyAyICAgYmx1ZSAgICAgMw0KIyAzICAgYmx1ZSAgICAgNA0KDQojIGZpbHRlciB2YWx1ZSBpbiAxIG9yIDQNCmZpbHRlcih0YmwsIHZhbHVlICVpbiUgYygxLDQpKQ0KIyBBIHRpYmJsZTogMiDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgICBibHVlICAgICA0DQoNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpvcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChvcmRlciw1KQ0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmhlYWQob3JkZXJfdGJsLCA1KQ0KDQojIGZpbHRlciBvcmRlciBkYXRhIGlzIDIwMDktMTAtMTMgcm93cw0KZmlsdGVyKG9yZGVyX3RibCwgb3JkZXJkYXRlID09ICIyMDA5LTEwLTEzIikNCg0KIyBmaWx0ZXIgb3JkZXIgZGF0YSBpcyAyMDA5LTEwLTEzIHJvd3MgYW5kIHRvdGFsIHByaWNlIGdyZWF0ZXIgdGhhbiAxMDAgcm93cywgMSByb3cgbWF0Y2ggYW5kIGFzc2lnbiB0byBmaWx0ZXJEYXRhDQpmaWx0ZXJEYXRhIDwtIGZpbHRlcihvcmRlcl90YmwsIG9yZGVyZGF0ZSA9PSAiMjAwOS0xMC0xMyIgJiB0b3RhbHByaWNlID4gMTAwKQ0KVmlldyhmaWx0ZXJEYXRhKQ0KYGBgDQoNCiMjIENoYXB0ZXI0IOWtkOmbhumAieWPluWHveaVsC0tc2VsZWN0DQpzZWxlY3QgY29sdW1ucy92YXJpYWJsZSBieSBuYW1lL21hdGNoIHJ1bGVzDQpgYGB7ciBzZWxlY3QgZnVuY3Rpb24gaW4gZHBseXJ9DQojIExvYWQgZHBseXIgcGFja2FnZSBpbiBhIHNhZmVyIHdheQ0KaWYoIXN1cHByZXNzV2FybmluZ3MocmVxdWlyZShkcGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ2RwbHlyJykNCiAgICByZXF1aXJlKGRwbHlyKQ0KfQ0KDQpkZiA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmKQ0KdGJsDQoNCiMganVzdCBzZWxlY3QgY29sb3IgY29sdW1uDQpzZWxlY3QodGJsLCBjb2xvcikNCiMgQSB0aWJibGU6IDUgw5cgMQ0KIyAgICBjb2xvcg0KIyAgIDxmY3RyPg0KIyAxICAgYmx1ZQ0KIyAyICBibGFjaw0KIyAzICAgYmx1ZQ0KIyA0ICAgYmx1ZQ0KIyA1ICBibGFjaw0KDQojIHNlbGVjdCBhbGwgb3RoZXIgY29sdW1ucyBleGNlcHQgY29sb3IgY29sdW1uIGVxdWFscyBzZWxlY3QgdmFsdWUgY29sdW1uDQpzZWxlY3QodGJsLCAtY29sb3IpDQojIEEgdGliYmxlOiA1IMOXIDENCiMgICB2YWx1ZQ0KIyAgIDxpbnQ+DQojIDEgICAgIDENCiMgMiAgICAgMg0KIyAzICAgICAzDQojIDQgICAgIDQNCiMgNSAgICAgNQ0KYGBgDQoNClVzZWZ1bCBmdW5jdGlvbiB0byBzZWxlY3QNCmBgYHtyIFVzZWZ1bCBmdW5jdGlvbiB0byBzZWxlY3R9DQpzdGFydHNfd2l0aCh4LCBpZ25vcmUuY2FzZSA9IFRSVUUpICMgY29sdW1uL3ZhcmlhYmxlIHN0YXJ0IHdpdGggY2hhcnQgeA0KZW5kc193aXRoKHgsIGlnbm9yZS5jYXNlID0gVFJVRSkgIyBjb2x1bW4vdmFyaWFibGUgZW5kIHdpdGggY2hhcnQgeA0KY29udGFpbnMoeCwgaWdub3JlLmNhc2UgPSBUUlVFKSAjIGNvbHVtbi92YXJpYWJsZSBjb250YWlucyBjaGFydCB4DQptYXRjaGVzKHgsIGlnbm9yZS5jYXNlID0gVFJVRSkgICMgY29sdW1uL3ZhcmlhYmxlIG1hdGNoZXMgcmVndWxhciBleHByZXNzaW9uIHgNCm51bV9yYW5nZSgieCIsIDE6NSwgd2lkdGggPSAyKSAgIyBjb2x1bW4vdmFyaWFibGUgZnJvbSB4MDEgdG8geDA1DQpvbmVfb2YoIngiLCAieSIsICJ6IikgIyBjb2x1bW4vdmFyaWFibGUgY29udGFpbnMgaW4geCwgeSwgeg0KZXZlcnl0aGluZygpICMgYWxsIGNvbHVtbi92YXJpYWJsZQ0KDQojIGUuZy4gb3JkZXJfdGJsLCBjaGVjayBjb2x1bW4NCm5hbWVzKG9yZGVyX3RibCkNCiAjIFsxXSAiWCIgICAgICAgICAgICAgIm9yZGVyaWQiICAgICAgICJjdXN0b21lcmlkIiAgICAiY2FtcGFpZ25pZCINCiAjIFs1XSAib3JkZXJkYXRlIiAgICAgImNpdHkiICAgICAgICAgICJzdGF0ZSIgICAgICAgICAiemlwY29kZSINCiAjIFs5XSAicGF5bWVudHR5cGUiICAgInRvdGFscHJpY2UiICAgICJudW1vcmRlcmxpbmVzIiAibnVtdW5pdHMiDQoNCiMgc2VsZWN0IG9yZGVyIGRhdGEgYW5kIHRvdGFsIHByaWNlDQpkYXRlX3ByaWNlIDwtIHNlbGVjdChvcmRlcl90Ymwsb3JkZXJkYXRlLCB0b3RhbHByaWNlKQ0KZGF0ZV9wcmljZQ0KDQojIHJlbmFtZSBjb2x1bW4gbmFtZSBhdCB0aGUgc2FtZSB0aW1lDQpkYXRlX3ByaWNlMiA8LSBzZWxlY3Qob3JkZXJfdGJsLGRhdGUgPSBvcmRlcmRhdGUsIHByaWNlID0gdG90YWxwcmljZSkNCmRhdGVfcHJpY2UyDQoNCiMgc2VsZWN0IHN0YXJ0cyB3aXRoIG9yZGVyIGNvbHVtbiBuYW1lDQpTdGFydF9XaXRoX09yZGVyIDwtIHNlbGVjdChvcmRlcl90Ymwsc3RhcnRzX3dpdGgoIm9yZGVyIixpZ25vcmUuY2FzZSA9IFRSVUUpKQ0KU3RhcnRfV2l0aF9PcmRlcg0KIyBBIHRpYmJsZTogMTAwLDAwMCDDlyAyDQojICAgIG9yZGVyaWQgIG9yZGVyZGF0ZQ0KIyAgICAgIDxpbnQ+ICAgICA8ZmN0cj4NCiMgMSAgMTAwMjg1NCAyMDA5LTEwLTEzDQojIDIgIDEwMDI4NTUgMjAwOS0xMC0xMw0KIyAzICAxMDAyODU2IDIwMTEtMDYtMDINCiMgNCAgMTAwMjg1NyAyMDA5LTEwLTE0DQojIDUgIDEwMDI4ODYgMjAxMC0xMS0xOQ0KIyA2ICAxMDAyODg3IDIwMDktMTAtMTUNCiMgNyAgMTAwMjg4OCAyMDA5LTEwLTE1DQojIDggIDEwMDI4ODkgMjAwOS0xMC0xNQ0KIyA5ICAxMDAyODkwIDIwMDktMTAtMTUNCiMgMTAgMTAwMzAwNCAyMDA5LTEwLTE1DQojIC4uLiB3aXRoIDk5LDk5MCBtb3JlIHJvd3MNCg0KIyBzZWxlY3QgY29udGFpbnMgaWQgY29sdW1uIG5hbWUNCkNvbnRhaW5zX0lEIDwtIHNlbGVjdChvcmRlcl90YmwsIGNvbnRhaW5zKCJpZCIsaWdub3JlLmNhc2UgPSBUUlVFKSkNCmhlYWQoQ29udGFpbnNfSUQsNSkNCiMgQSB0aWJibGU6IDUgw5cgMw0KIyAgIG9yZGVyaWQgY3VzdG9tZXJpZCBjYW1wYWlnbmlkDQojICAgICA8aW50PiAgICAgIDxpbnQ+ICAgICAgPGludD4NCiMgMSAxMDAyODU0ICAgICAgNDU5NzggICAgICAgMjE0MQ0KIyAyIDEwMDI4NTUgICAgIDEyNTM4MSAgICAgICAyMTczDQojIDMgMTAwMjg1NiAgICAgMTAzMTIyICAgICAgIDIxNDENCiMgNCAxMDAyODU3ICAgICAxMzA5ODAgICAgICAgMjE3Mw0KIyA1IDEwMDI4ODYgICAgICA0ODU1MyAgICAgICAyMTQxDQoNCiMgcmVuYW1lIGZ1bmN0aW9uDQphcy5kYXRhLmZyYW1lKENvbnRhaW5zX0lEKQ0KIyByZW5hbWUgdGhlIG5ldyBuYW1lIG11c3QgYXQgdGhlIGxlZnQNCmFmdGVyX3JlbmFtZSA8LSByZW5hbWUoQ29udGFpbnNfSUQsIG9vSUQgPSBvcmRlcmlkLCBvb0lEID0gY3VzdG9tZXJpZCwgb29DQUlEID0gIGNhbXBhaWduaWQpDQpoZWFkKENvbnRhaW5zX0lELDUpDQojIEEgdGliYmxlOiA1IMOXIDMNCiMgICBvcmRlcmlkIGN1c3RvbWVyaWQgY2FtcGFpZ25pZA0KIyAgICAgPGludD4gICAgICA8aW50PiAgICAgIDxpbnQ+DQojIDEgMTAwMjg1NCAgICAgIDQ1OTc4ICAgICAgIDIxNDENCiMgMiAxMDAyODU1ICAgICAxMjUzODEgICAgICAgMjE3Mw0KIyAzIDEwMDI4NTYgICAgIDEwMzEyMiAgICAgICAyMTQxDQojIDQgMTAwMjg1NyAgICAgMTMwOTgwICAgICAgIDIxNzMNCiMgNSAxMDAyODg2ICAgICAgNDg1NTMgICAgICAgMjE0MQ0KDQojIGFmdGVyIHJlbmFtZSByZXR1cm5zIGEgbmV3IHRibCwgdGhlIG9yaWdpbiBDb250YWluc19JRCB3aWxsIG5vdCBiZSBjaGFuZ2VkDQpoZWFkKGFmdGVyX3JlbmFtZSw1KQ0KIyBBIHRpYmJsZTogNSDDlyAzDQojICAgICAgb29JRCAgIG9vSUQgb29DQUlEDQojICAgICA8aW50PiAgPGludD4gIDxpbnQ+DQojIDEgMTAwMjg1NCAgNDU5NzggICAyMTQxDQojIDIgMTAwMjg1NSAxMjUzODEgICAyMTczDQojIDMgMTAwMjg1NiAxMDMxMjIgICAyMTQxDQojIDQgMTAwMjg1NyAxMzA5ODAgICAyMTczDQojIDUgMTAwMjg4NiAgNDg1NTMgICAyMTQxDQojIHRoaXMgd29ya3MgaW4gdGhlIGNvZGUgYmVsb3cNCmhlYWQocmVuYW1lKGlyaXMsIHB0ID0gUGV0YWwuTGVuZ3RoKSw1KQ0KDQojIGUuZy4gd2l0aCBzZWxlY3QgZnJvbSA/IHJlbmFtZQ0KaXJpcyA8LSB0YmxfZGYoaXJpcykgIyBzbyBpdCBwcmludHMgYSBsaXR0bGUgbmljZXINCnNlbGVjdChpcmlzLCBzdGFydHNfd2l0aCgiUGV0YWwiKSkNCnNlbGVjdChpcmlzLCBlbmRzX3dpdGgoIldpZHRoIikpDQpzZWxlY3QoaXJpcywgY29udGFpbnMoImV0YWwiKSkNCnNlbGVjdChpcmlzLCBtYXRjaGVzKCIudC4iKSkNCnNlbGVjdChpcmlzLCBQZXRhbC5MZW5ndGgsIFBldGFsLldpZHRoKQ0KdmFycyA8LSBjKCJQZXRhbC5MZW5ndGgiLCAiUGV0YWwuV2lkdGgiKQ0Kc2VsZWN0KGlyaXMsIG9uZV9vZih2YXJzKSkNCg0KZGYgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXgocnVuaWYoMTAwKSwgbnJvdyA9IDEwKSkNCmRmIDwtIHRibF9kZihkZltjKDMsIDQsIDcsIDEsIDksIDgsIDUsIDIsIDYsIDEwKV0pDQpzZWxlY3QoZGYsIFY0OlY2KQ0Kc2VsZWN0KGRmLCBudW1fcmFuZ2UoIlYiLCA0OjYpKQ0KDQojIERyb3AgdmFyaWFibGVzDQpzZWxlY3QoaXJpcywgLXN0YXJ0c193aXRoKCJQZXRhbCIpKQ0Kc2VsZWN0KGlyaXMsIC1lbmRzX3dpdGgoIldpZHRoIikpDQpzZWxlY3QoaXJpcywgLWNvbnRhaW5zKCJldGFsIikpDQpzZWxlY3QoaXJpcywgLW1hdGNoZXMoIi50LiIpKQ0Kc2VsZWN0KGlyaXMsIC1QZXRhbC5MZW5ndGgsIC1QZXRhbC5XaWR0aCkNCg0KIyBSZW5hbWUgdmFyaWFibGVzOg0KIyAqIHNlbGVjdCgpIGtlZXBzIG9ubHkgdGhlIHZhcmlhYmxlcyB5b3Ugc3BlY2lmeQ0Kc2VsZWN0KGlyaXMsIHBldGFsX2xlbmd0aCA9IFBldGFsLkxlbmd0aCkNCiMgUmVuYW1pbmcgbXVsdGlwbGUgdmFyaWFibGVzIHVzZXMgYSBwcmVmaXg6DQpzZWxlY3QoaXJpcywgcGV0YWwgPSBzdGFydHNfd2l0aCgiUGV0YWwiKSkNCg0KIyBSZW9yZGVyIHZhcmlhYmxlczoga2VlcCB0aGUgdmFyaWFibGUgIlNwZWNpZXMiIGluIHRoZSBmcm9udA0Kc2VsZWN0KGlyaXMsIFNwZWNpZXMsIGV2ZXJ5dGhpbmcoKSkNCg0KIyAqIHJlbmFtZSgpIGtlZXBzIGFsbCB2YXJpYWJsZXMNCnJlbmFtZShpcmlzLCBwZXRhbF9sZW5ndGggPSBQZXRhbC5MZW5ndGgpDQoNCiMgUHJvZ3JhbW1pbmcgd2l0aCBzZWxlY3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpzZWxlY3RfKGlyaXMsIH5QZXRhbC5MZW5ndGgpDQpzZWxlY3RfKGlyaXMsICJQZXRhbC5MZW5ndGgiKQ0Kc2VsZWN0XyhpcmlzLCBsYXp5ZXZhbDo6aW50ZXJwKH5tYXRjaGVzKHgpLCB4ID0gIi50LiIpKQ0Kc2VsZWN0XyhpcmlzLCBxdW90ZSgtUGV0YWwuTGVuZ3RoKSwgcXVvdGUoLVBldGFsLldpZHRoKSkNCnNlbGVjdF8oaXJpcywgLmRvdHMgPSBsaXN0KHF1b3RlKC1QZXRhbC5MZW5ndGgpLCBxdW90ZSgtUGV0YWwuV2lkdGgpKSkNCmBgYA0KDQojIyBDaGFwdGVyNSDmlbDmja7nmoTmjpLluo8tLWFycmFuZ2Xlh73mlbANCnRyYWRpdGlvbmFsIG1ldGhvZDogb3JkZXIgZnVuY3Rpb24NCmBgYHtyIHVzZSBvcmRlciB0byBvcmRlcn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlIGluIGEgc2FmZXIgd2F5DQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmMSkNCnRibA0KIyBBIHRpYmJsZTogNSDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgIGJsYWNrICAgICAyDQojIDMgICBibHVlICAgICAzDQojIDQgICBibHVlICAgICA0DQojIDUgIGJsYWNrICAgICA1DQoNCiMgb3JkZXIgdXNlIGluZGV4DQpkZl9vcmRlciA8LSBvcmRlcihkZjEkY29sb3IpDQpkZl9vcmRlcg0KIyBbMV0gMiA1IDEgMyA0DQpkZjFbZGZfb3JkZXIsXQ0KIyAgIGNvbG9yIHZhbHVlDQojIDIgYmxhY2sgICAgIDINCiMgNSBibGFjayAgICAgNQ0KIyAxICBibHVlICAgICAxDQojIDMgIGJsdWUgICAgIDMNCiMgNCAgYmx1ZSAgICAgNA0KDQojIHVzZSBhcnJhbmdlIHRvIG9yZGVyIGEgZGF0YSBmcmFtZS90YmwsIGRlZmF1bHQgaXMgYWVzYywgMSB0byAzDQphcnJhbmdlKGRmMSwgY29sb3IpDQojIHVzZSBkZXNjIHRvIG9yZGVyIGJ5IDMgdG8gMQ0KYXJyYW5nZShkZjEsIGRlc2MoY29sb3IpKQ0KDQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCg0KIyBvcmRlciBieSBkYXRlDQp0YmwgPC0gc2VsZWN0KG9yZGVyX3RibCwgb2RhdGUgPSBvcmRlcmRhdGUsIG9wcmljZSA9IHRvdGFscHJpY2UpDQphcnJhbmdlKHRibCwgb2RhdGUpDQojIEEgdGliYmxlOiAxMDAsMDAwIMOXIDINCiMgICAgICAgICBvZGF0ZSBvcHJpY2UNCiMgICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAgMjAwOS0xMC0wNCAgICAyMDANCiMgMiAgMjAwOS0xMC0wNCAgICAxMjANCiMgMyAgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAgMjAwOS0xMC0wNCAgICAxMDANCiMgNSAgMjAwOS0xMC0wNCAgICAgNzANCiMgNiAgMjAwOS0xMC0wNCAgICAgNTANCiMgNyAgMjAwOS0xMC0wNCAgICAgNTANCiMgOCAgMjAwOS0xMC0wNCAgICAgNDANCiMgOSAgMjAwOS0xMC0wNCAgICAgNDANCiMgMTAgMjAwOS0xMC0wNCAgICAgNDANCiMgLi4uIHdpdGggOTksOTkwIG1vcmUgcm93cw0KDQojIG9yZGVyIGJ5IGRhdGUgJiBieSBwcmljZSBkZXNjIDMgdG8gMQ0KYXJyYW5nZSh0YmwsIG9kYXRlLCBkZXNjKG9wcmljZSkpDQojIEEgdGliYmxlOiAxMDAsMDAwIMOXIDINCiMgICAgICAgICBvZGF0ZSBvcHJpY2UNCiMgICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAgMjAwOS0xMC0wNCAgICAyMDANCiMgMiAgMjAwOS0xMC0wNCAgICAxMjANCiMgMyAgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAgMjAwOS0xMC0wNCAgICAxMDANCiMgNSAgMjAwOS0xMC0wNCAgICAgNzANCiMgNiAgMjAwOS0xMC0wNCAgICAgNTANCiMgNyAgMjAwOS0xMC0wNCAgICAgNTANCiMgOCAgMjAwOS0xMC0wNCAgICAgNDANCiMgOSAgMjAwOS0xMC0wNCAgICAgNDANCiMgMTAgMjAwOS0xMC0wNCAgICAgNDANCiMgLi4uIHdpdGggOTksOTkwIG1vcmUgcm93cw0KYGBgDQoNCiMjIENoYXB0ZXI2IOaVsOaNruaJqeWxlS0tbXV0YXRl5Ye95pWwDQrmlbDmja7mianlsZXvvIzkv53nlZnljp/mnaXnmoTlj5jph4/jgIHliJfnmoTln7rnoYDkuIrlop7liqDlj5jph4/miJbogIXliJcNCmBgYHtyIG11dGF0ZSBmdW5jdGlvbn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlIGluIGEgc2FmZXIgd2F5DQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0YmwgPC0gdGJsX2RmKGRmMSkNCnRibA0KIyBBIHRpYmJsZTogNSDDlyAyDQojICAgIGNvbG9yIHZhbHVlDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgICBibHVlICAgICAxDQojIDIgIGJsYWNrICAgICAyDQojIDMgICBibHVlICAgICAzDQojIDQgICBibHVlICAgICA0DQojIDUgIGJsYWNrICAgICA1DQoNCiMgYWRkIGRvdWJsZSBjb2x1bW4NCm11dGF0ZSh0YmwsIGRvdWJsZSA9IDIgKiB2YWx1ZSkNCiMgQSB0aWJibGU6IDUgw5cgMw0KIyAgICBjb2xvciB2YWx1ZSBkb3VibGUNCiMgICA8ZmN0cj4gPGludD4gIDxkYmw+DQojIDEgICBibHVlICAgICAxICAgICAgMg0KIyAyICBibGFjayAgICAgMiAgICAgIDQNCiMgMyAgIGJsdWUgICAgIDMgICAgICA2DQojIDQgICBibHVlICAgICA0ICAgICAgOA0KIyA1ICBibGFjayAgICAgNSAgICAgMTANCg0KIyBhZGQgZG91YmxlIGNvbHVtbiBhbmQgcXVhZHJ1cGxlIGNvbHVtbg0KbXV0YXRlKHRibCwgZG91YmxlID0gMiAqIHZhbHVlLCBxdWFkcnVwbGUgPSA0ICogdmFsdWUpDQojIEEgdGliYmxlOiA1IMOXIDQNCiMgICAgY29sb3IgdmFsdWUgZG91YmxlIHF1YWRydXBsZQ0KIyAgIDxmY3RyPiA8aW50PiAgPGRibD4gICAgIDxkYmw+DQojIDEgICBibHVlICAgICAxICAgICAgMiAgICAgICAgIDQNCiMgMiAgYmxhY2sgICAgIDIgICAgICA0ICAgICAgICAgOA0KIyAzICAgYmx1ZSAgICAgMyAgICAgIDYgICAgICAgIDEyDQojIDQgICBibHVlICAgICA0ICAgICAgOCAgICAgICAgMTYNCiMgNSAgYmxhY2sgICAgIDUgICAgIDEwICAgICAgICAyMA0KDQojIHVzZSBvcmRlciBkYXRhIHNldCB0byBtdXRhdGUgeWVhciwgbW9udGggYW5kIGRhdGUNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpvcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChvcmRlciw1KQ0Kb3JkZXJfdGJsIDwtIHRibF9kZihvcmRlcikNCmhlYWQob3JkZXJfdGJsLCA1KQ0KdGJsIDwtIHNlbGVjdChvcmRlcl90YmwsIG9kYXRlID0gb3JkZXJkYXRlLCBvcHJpY2UgPSB0b3RhbHByaWNlKQ0KdGJsIDwtIGFycmFuZ2UodGJsLCBvZGF0ZSwgZGVzYyhvcHJpY2UpKQ0KaGVhZCh0YmwsIDUpDQojICMgQSB0aWJibGU6IDUgw5cgMg0KIyAgICAgICAgb2RhdGUgb3ByaWNlDQojICAgICAgIDxmY3RyPiAgPGRibD4NCiMgMSAyMDA5LTEwLTA0ICAgIDIwMA0KIyAyIDIwMDktMTAtMDQgICAgMTIwDQojIDMgMjAwOS0xMC0wNCAgICAxMDANCiMgNCAyMDA5LTEwLTA0ICAgIDEwMA0KIyA1IDIwMDktMTAtMDQgICAgIDcwDQoNCiMgbXV0YXRlDQp0YmxfTmV3IDwtIG11dGF0ZSh0YmwsIG9ZZWFyID0gc3Vic3RyKG9kYXRlLCAxLCA0KSwgb01vbnRoID0gc3Vic3RyKG9kYXRlLCA2LCA3KSxvRGF0ZSA9IHN1YnN0cihvZGF0ZSwgOSwgMTApKQ0KaGVhZCh0YmxfTmV3LDUpDQojIEEgdGliYmxlOiA1IMOXIDUNCiMgICAgICAgIG9kYXRlIG9wcmljZSBvWWVhciBvTW9udGggb0RhdGUNCiMgICAgICAgPGZjdHI+ICA8ZGJsPiA8Y2hyPiAgPGNocj4gPGNocj4NCiMgMSAyMDA5LTEwLTA0ICAgIDIwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgMiAyMDA5LTEwLTA0ICAgIDEyMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgMyAyMDA5LTEwLTA0ICAgIDEwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgNCAyMDA5LTEwLTA0ICAgIDEwMCAgMjAwOSAgICAgMTAgICAgMDQNCiMgNSAyMDA5LTEwLTA0ICAgICA3MCAgMjAwOSAgICAgMTAgICAgMDQNCg0KIyB0cmFuc211dGUNCiMgTXV0YXRlIGFkZHMgbmV3IHZhcmlhYmxlcyBhbmQgcHJlc2VydmVzIGV4aXN0aW5nOw0KIyB0cmFuc211dGUgZHJvcHMgZXhpc3RpbmcgdmFyaWFibGVzLg0KZGYxIDwtIGRhdGEuZnJhbWUoDQogIGNvbG9yID0gYygiYmx1ZSIsICJibGFjayIsICJibHVlIiwgImJsdWUiLCAiYmxhY2siKSwNCiAgdmFsdWUgPSAxOjUNCikNCnRibF90cmFuc211dGUgPC0gdGJsX2RmKGRmMSkNCnRibF90cmFuc211dGUNCiMgQSB0aWJibGU6IDUgw5cgMg0KIyAgICBjb2xvciB2YWx1ZQ0KIyAgIDxmY3RyPiA8aW50Pg0KIyAxICAgYmx1ZSAgICAgMQ0KIyAyICBibGFjayAgICAgMg0KIyAzICAgYmx1ZSAgICAgMw0KIyA0ICAgYmx1ZSAgICAgNA0KIyA1ICBibGFjayAgICAgNQ0KDQp0cmFuc211dGUodGJsX3RyYW5zbXV0ZSwgZG91YmxlID0gMiAqIHZhbHVlLCBxdWFkcnVwbGUgPSA0ICogdmFsdWUpDQojIEEgdGliYmxlOiA1IMOXIDINCiMgICBkb3VibGUgcXVhZHJ1cGxlDQojICAgIDxkYmw+ICAgICA8ZGJsPg0KIyAxICAgICAgMiAgICAgICAgIDQNCiMgMiAgICAgIDQgICAgICAgICA4DQojIDMgICAgICA2ICAgICAgICAxMg0KIyA0ICAgICAgOCAgICAgICAgMTYNCiMgNSAgICAgMTAgICAgICAgIDIwDQpgYGANCg0KIyMgQ2hhcHRlcjcg5pWw5o2u5rGH5oC7LS1zdW1tYXJpc2Xlh73mlbANCuaVsOaNruaxh+aAuy3lsIblpJrkuKrlgLzmsYfmgLvkuLrkuIDkuKrmlbDmja7lgLwNCmBgYHtyIHN1bW1hcmlzZX0NCmRmMSA8LSBkYXRhLmZyYW1lKA0KICBjb2xvciA9IGMoImJsdWUiLCAiYmxhY2siLCAiYmx1ZSIsICJibHVlIiwgImJsYWNrIiksDQogIHZhbHVlID0gMTo1DQopDQp0Ymxfc3VtbWFyaXNlIDwtIHRibF9kZihkZjEpDQoNCnN1bW1hcmlzZSh0Ymxfc3VtbWFyaXNlLCB0b3RhbCA9IHN1bSh2YWx1ZSkpDQojIEEgdGliYmxlOiAxIMOXIDENCiMgICB0b3RhbA0KIyAgIDxpbnQ+DQojIDEgICAgMTUNCg0KIyBtdWx0aSBwYXJhbWV0ZXINCnN1bW1hcmlzZSh0Ymxfc3VtbWFyaXNlLCB0b3RhbF92YWx1ZSA9IHN1bSh2YWx1ZSksIG1lYW5fdmFsdWUgPSBtZWFuKHZhbHVlKSwgc2RfdmFsdWUgPSBzZCh2YWx1ZSkpDQojIEEgdGliYmxlOiAxIMOXIDMNCiMgICB0b3RhbF92YWx1ZSBtZWFuX3ZhbHVlIHNkX3ZhbHVlDQojICAgICAgICAgPGludD4gICAgICA8ZGJsPiAgICA8ZGJsPg0KIyAxICAgICAgICAgIDE1ICAgICAgICAgIDMgMS41ODExMzkNCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQgdG8gc3VtbWFyaXNlDQojIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQob3JkZXIsNSkNCm9yZGVyX3RibCA8LSB0YmxfZGYob3JkZXIpDQpoZWFkKG9yZGVyX3RibCwgNSkNCnRibCA8LSBzZWxlY3Qob3JkZXJfdGJsLCBvZGF0ZSA9IG9yZGVyZGF0ZSwgb3ByaWNlID0gdG90YWxwcmljZSkNCiMgdGJsIDwtIGFycmFuZ2UodGJsLCBvZGF0ZSwgZGVzYyhvcHJpY2UpKQ0Kc3VtbWFyaXNlKHRibCwgbWF4ID0gbWF4KG9wcmljZSksDQogICAgICAgICAgICAgIG1pbiA9IG1pbihvcHJpY2UpLA0KICAgICAgICAgICAgICBtZWFuID0gbWVhbihvcHJpY2UpKQ0KIyBBIHRpYmJsZTogMSDDlyAzDQojICAgICBtYXggICBtaW4gICAgIG1lYW4NCiMgICA8ZGJsPiA8ZGJsPiAgICA8ZGJsPg0KIyAxICA2NzgwICAgICAwIDYwLjc3NzczDQoNCmBgYA0Kc3VtbWFyaXNlKCnkuK3nmoTmsYfmgLvlh73mlbDlsIbkuIDliJflgLzovazmjaLkuLrkuIDkuKrljZXni6znmoTlgLzovpPlh7oNClLoh6rluKbnmoTnu5/orqHlh73mlbDpg73mmK/lj6/ku6Xkvb/nlKjnmoQNCm1pbigpLCBtYXgoKSwgbWVhbigpLCBzdW0oKSwgc2QoKSwgbWVkaWFuKCksIElRUigpDQoNCuatpOWklu+8jGRwbHly6L+Y5o+Q5L6b5LqG5LiA5Lqb5YW25LuW5Lya55So5Yiw55qE5Ye95pWwDQpuKCk66KeC5rWL5YC855qE5Liq5pWwDQpuX2Rpc3RpbmN0KHgpOuS4jeebuOWQjOeahOingua1i+WAvOeahOS4quaVsA0KZmlyc3QoeCksbGFzdCh4KeWSjG50aCh4LCBuKeiOt+WPluesrOS4gOS4qu+8jOacgOWQjuS4gOS4qu+8jOWSjOesrG7kuKrmlbDmja4NCg0KYGBge3IgZmlyc3QgYW5kIGxhc3QgdmFsdWV9DQpzdW1tYXJpc2UodGJsLCBmaXJzdCA9IGZpcnN0KG9kYXRlKSwgbGFzdCA9IGxhc3Qob2RhdGUpKQ0KIyBBIHRpYmJsZTogMSDDlyAyDQojICAgICAgICBmaXJzdCAgICAgICBsYXN0DQojICAgICAgIDxmY3RyPiAgICAgPGZjdHI+DQojIDEgMjAwOS0xMC0xMyAyMDE0LTA0LTI4DQpgYGANCg0KIyMgQ2hhcHRlcjgg5pWw5o2u6L+e5o6lLS1qb2lu5Ye95pWwDQpkcGx5ciBhZHZhbmNlZCBmdW5jdGlvbjoNCi0gZGF0YSBzZXQgam9pbi9jb25uZWN0aW9uLCBsaWtlIGV4Y2VsIHZsb29rdXAgZnVuY3Rpb24NCi0gZ3JvdXBfYnkNCi0gcGlwZSBmdW5jdGlvbjogJT4lDQotIG90aGVyIGZ1bmN0aW9uOiBkbywgcGx5cjo6Y29sd2lzZQ0KLSBteXNxbCBkYXRhYmFzZSBjb25uZWN0aW9uDQoNCmBgYHtyIGpvaW59DQp4IDwtIGRhdGEuZnJhbWUobmFtZSA9IGMoIkpvaG4iLCAiUGF1bCIsICJHZW9yZ2UiLCAiUmluZ28iLCAiU3R1YXJ0IiwgIlNpcWluIiksDQogICAgICAgICAgICAgICAgaW5zdHJ1bWVudCA9IGMoImd1aXRhciIsICJiYXNzIiwgImd1aXRhciIsICJkcnVtcyIsICJiYXNzIiwgImRydW1zIikpDQp4DQojICAgICBuYW1lIGluc3RydW1lbnQNCiMgMSAgIEpvaG4gICAgIGd1aXRhcg0KIyAyICAgUGF1bCAgICAgICBiYXNzDQojIDMgR2VvcmdlICAgICBndWl0YXINCiMgNCAgUmluZ28gICAgICBkcnVtcw0KIyA1IFN0dWFydCAgICAgICBiYXNzDQojIDYgIFNpcWluICAgICAgZHJ1bXMNCnkgPC0gZGF0YS5mcmFtZShuYW1lID0gYygiSm9obiIsICJQYXVsIiwgIkdlb3JnZSIsICJSaW5nbyIsICJCcmlhbiIpLA0KICAgICAgICAgICAgICAgIGJhbmQgPSBjKFQsIFQsIFQsIFQsIFQpKQ0KeQ0KIyAgICAgbmFtZSBiYW5kDQojIDEgICBKb2huIFRSVUUNCiMgMiAgIFBhdWwgVFJVRQ0KIyAzIEdlb3JnZSBUUlVFDQojIDQgIFJpbmdvIFRSVUUNCiMgNSAgQnJpYW4gVFJVRQ0KDQojIGxlZnRfam9pbiBsaWtlIGV4Y2VsIHZsb29rdXAsIGFsbCB2YWx1ZSBpbiBsZWZ0IHRhYmxlIHdpbGwgcmVtYWluLCBidXQgbm90IG1hdGNoIHZhbHVlIGluIHJpZ2h0IHRhYmxlIHdpbGwgYmUgc2V0IE5BDQpsZWZ0X2pvaW4oeCwgeSwgYnkgPSAibmFtZSIpDQojICAgICBuYW1lIGluc3RydW1lbnQgYmFuZA0KIyAxICAgSm9obiAgICAgZ3VpdGFyIFRSVUUNCiMgMiAgIFBhdWwgICAgICAgYmFzcyBUUlVFDQojIDMgR2VvcmdlICAgICBndWl0YXIgVFJVRQ0KIyA0ICBSaW5nbyAgICAgIGRydW1zIFRSVUUNCiMgNSBTdHVhcnQgICAgICAgYmFzcyAgIE5BDQojIDYgIFNpcWluICAgICAgZHJ1bXMgICBOQQ0KDQojIGlubmVyX2pvaW4sIGp1c3QgcmVtYWluIGxlZnQgYW5kIHJpZ2h0IHRhYmxlIG1hdGNoIHZhbHVlLA0KIyBhbmQgYWRkIGNvbHVtbihyaWdodCB0YWJsZSBkYXRhKSBpbiBsZWZ0IHRhYmxlDQojIGFuZCBub3QgbWF0Y2ggdmFsdWUgaW4gbGVmdCB0YWJsZSB3aWxsIGJlIGRpc2NhcmRlZA0KaW5uZXJfam9pbih4LCB5LCBieSA9ICJuYW1lIikNCiMgICAgIG5hbWUgaW5zdHJ1bWVudCBiYW5kDQojIDEgICBKb2huICAgICBndWl0YXIgVFJVRQ0KIyAyICAgUGF1bCAgICAgICBiYXNzIFRSVUUNCiMgMyBHZW9yZ2UgICAgIGd1aXRhciBUUlVFDQojIDQgIFJpbmdvICAgICAgZHJ1bXMgVFJVRQ0KDQojIHNlbWlfam9pbiwganVzdCByZW1haW4gbGVmdCB0YWJsZSB0aGF0IG1hdGNoZXMgdGhlIHZhbHVlIGluIHJpZ2h0IHRhYmxlLCBhbmQgcmlnaHQgdGFibGUgdmFsdWUgd2lsbCBub3QgdXNlZA0Kc2VtaV9qb2luKHgsIHksIGJ5ID0gIm5hbWUiKQ0KIyAgICAgbmFtZSBpbnN0cnVtZW50DQojIDEgICBKb2huICAgICBndWl0YXINCiMgMiAgIFBhdWwgICAgICAgYmFzcw0KIyAzIEdlb3JnZSAgICAgZ3VpdGFyDQojIDQgIFJpbmdvICAgICAgZHJ1bXMNCg0KIyBhbnRpX2pvaW4sIGp1c3QgY29udmVydCB3aXRoIHNlbWlfam9pbiwganVzdCBrZWVwIG1hdGNoIHZhbHVlcyBpbiByaWdodCB0YWJsZQ0KYW50aV9qb2luKHgsIHksIGJ5ID0gIm5hbWUiKQ0KIyAgICAgbmFtZSBpbnN0cnVtZW50DQojIDEgIFNpcWluICAgICAgZHJ1bXMNCiMgMiBTdHVhcnQgICAgICAgYmFzcw0KDQojIHVzZSBvcmRlciBhbmQgY3VzdGltZXIgZGF0YSBzZXQgdG8gam9pbg0KIyBpbXBvcnQgZGF0YSBhbmQgY2hhbmdlIHRvIHRibCBvYmplY3QNCmRmX29yZGVyIDwtIHJlYWQuY3N2KCJkcGx5ci1kYXRhL29yZGVyLmNzdiIpDQpkZl9jdXN0b21lciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9jdXN0b21lci5jc3YiKQ0KaGVhZChkZl9vcmRlciw1KQ0KaGVhZChkZl9jdXN0b21lciw1KQ0KDQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KdGJsX2N1c3RvbWVyIDwtIHRibF9kZihkZl9jdXN0b21lcikNCg0Kc19vcmRlciA8LSBzZWxlY3QodGJsX29yZGVyLCBvZGF0ZSA9IG9yZGVyZGF0ZSwgb2N1c3RfaWQgPSBjdXN0b21lcmlkKQ0Kc19jdXN0b21lciA8LSBzZWxlY3QodGJsX2N1c3RvbWVyLCBvY3VzdF9pZCA9IGN1c3RvbWVyaWQsIGdlbmRlciwgZmlyc3RuYW1lLGxhc3RuYW1lID1MYXN0bmFtZSkNCg0KYXJyYW5nZShsZWZ0X2pvaW4oc19vcmRlciwgc19jdXN0b21lciwgYnkgPSAib2N1c3RfaWQiKSwgZmlyc3RuYW1lKQ0KYGBgDQoNCiMjIENoYXB0ZXI5IOWIhuexu+axh+aAuyAtLSBncm91cF9ieQ0K5YiG57G75rGH5oC7IC0tIGdyb3VwX2J5DQpgYGB7ciBncm91cF9ieSBmdW5jdGlvbn0NCiNzdW1tYXJ5IGJ5IHllYXItLUdyb3VwLXdpc2Ugc3VtbWFyeQ0KIyBncm91cF9ieSgp6L2s5Y+Y5oiQ5LiAIOS4quWIhuWlvee7hOeahOaVsOaNruahhg0KDQpkZjEgPC0gZGF0YS5mcmFtZSgNCiAgY29sb3IgPSBjKCJibHVlIiwgImJsYWNrIiwgImJsdWUiLCAiYmx1ZSIsICJibGFjayIpLA0KICB2YWx1ZSA9IDE6NQ0KKQ0Kc3VtbWFyaXNlKGRmMSwgdG90YWwgPXN1bSh2YWx1ZSkpDQojIGp1c3QgZ2V0IG9uZSBzdW1hcmlzZWQgZGF0YSB0b3RhbA0KIyAgIHRvdGFsDQojIDEgICAgMTUNCg0KIyBncm91cCBieSBjb2xvcg0KYnlfY29sb3IgPC0gZ3JvdXBfYnkoZGYxLCBjb2xvcikNCiMgdGhlbiBzdW1tYXJpc2UgYnkgZ3JvdXANCnN1bW1hcmlzZShieV9jb2xvciwgdG90YWwgPSBzdW0odmFsdWUpKQ0KIyBBIHRpYmJsZTogMiDDlyAyDQojICAgIGNvbG9yIHRvdGFsDQojICAgPGZjdHI+IDxpbnQ+DQojIDEgIGJsYWNrICAgICA3DQojIDIgICBibHVlICAgICA4DQoNCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQNCiMgaW1wb3J0IGRhdGEgYW5kIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQpkZl9vcmRlciA8LSByZWFkLmNzdigiZHBseXItZGF0YS9vcmRlci5jc3YiKQ0KaGVhZChkZl9vcmRlciw1KQ0KDQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KIyB0YmxfY3VzdG9tZXIgPC0gdGJsX2RmKGRmX2N1c3RvbWVyKQ0KDQpzX29yZGVyIDwtIHNlbGVjdCh0Ymxfb3JkZXIsIG9kYXRlID0gb3JkZXJkYXRlLCBvcHJpY2UgPSB0b3RhbHByaWNlKQ0KDQojIG11dGF0ZSB5ZWFyIGFuZCBtb250aCBjb2x1bW4NCm1fb3JkZXIgPC0gbXV0YXRlKHNfb3JkZXIsDQogICAgICAgICAgICAgICAgICBveWVhciA9IHN1YnN0cihvZGF0ZSwgMSwgNCksDQogICAgICAgICAgICAgICAgICBvbW9udGggPSBzdWJzdHIob2RhdGUsIDYsIDcpKQ0KaGVhZChtX29yZGVyLCA1KQ0KDQojIGdyb3VwIGJ5IHllYXINCm1fb3JkZXJfeWVhciA8LSBncm91cF9ieShtX29yZGVyLCBveWVhcikNCmhlYWQobV9vcmRlcl95ZWFyKQ0KIyBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzYgeCA0XQ0KIyBHcm91cHM6IG95ZWFyIFszXQ0KIw0KIyAgICAgICAgb2RhdGUgb3ByaWNlIG95ZWFyIG9tb250aA0KIyAgICAgICA8ZmN0cj4gIDxkYmw+IDxjaHI+ICA8Y2hyPg0KIyAxIDIwMDktMTAtMTMgMTkwLjAwICAyMDA5ICAgICAxMA0KIyAyIDIwMDktMTAtMTMgIDEwLjAwICAyMDA5ICAgICAxMA0KIyAzIDIwMTEtMDYtMDIgIDM1LjIyICAyMDExICAgICAwNg0KIyA0IDIwMDktMTAtMTQgIDEwLjAwICAyMDA5ICAgICAxMA0KIyA1IDIwMTAtMTEtMTkgIDEwLjAwICAyMDEwICAgICAxMQ0KIyA2IDIwMDktMTAtMTUgIDEwLjAwICAyMDA5ICAgICAxMA0KDQojIHN1bW1hcnkgeWVhcmx5IHByaWNlIGFuZCBhdmVyYWdlIHByaWNlLCBhbmQgbWF4IG1vbnRoIGZvciBjaGVjayBkYXRhIHBlcmlvZCh5ZWFyIDIwMTQganVzdCBoYXZlIDUgbW9udGgpDQojIHN1bW1hcmlzZSBzdXBwb3J0IG11bHRpIHBhcmFtZXRlcg0Kc3VtbWFyaXNlKG1fb3JkZXJfeWVhciwNCiAgICAgICAgICB5ZWFybHlfcHJpY2UgPSBzdW0ob3ByaWNlKSwNCiAgICAgICAgICBhdmVyYWdlX3ByaWNlID0gbWVhbihvcHJpY2UpLA0KICAgICAgICAgIE1heF9Nb250aCA9IG1heChvbW9udGgpKQ0KIyBBIHRpYmJsZTogNiDDlyA0DQojICAgb3llYXIgeWVhcmx5X3ByaWNlIGF2ZXJhZ2VfcHJpY2UgYG1heChvbW9udGgpYA0KIyAgIDxjaHI+ICAgICAgICA8ZGJsPiAgICAgICAgIDxkYmw+ICAgICAgICAgPGNocj4NCiMgMSAgMjAwOSAgICAgMjYyNjI3LjUgICAgICAzNC4xMzg1MCAgICAgICAgICAgIDEyDQojIDIgIDIwMTAgICAgIDk2NzQyOS4yICAgICAgNTIuMjM5ODIgICAgICAgICAgICAxMg0KIyAzICAyMDExICAgIDEzODA2MzYuNiAgICAgIDUxLjM1MzQyICAgICAgICAgICAgMTINCiMgNCAgMjAxMiAgICAxNDA0MTEzLjEgICAgICA2OC40MDk5MCAgICAgICAgICAgIDEyDQojIDUgIDIwMTMgICAgMTYzMzAwNC44ICAgICAgNzYuNzEwMTEgICAgICAgICAgICAxMg0KIyA2ICAyMDE0ICAgICA0Mjk5NjIuMCAgICAgIDg0LjQ3MTkwICAgICAgICAgICAgMDUNCmBgYA0KDQojIyBDaGFwdGVyMTAg566h6YGT5Ye95pWwDQolPiUgb3IgJS4lIHVzZSB0aGUgcHJldmlvdXMgZnVuY3Rpb24obGVmdCkncyBvdXQgcHV0IGFzIHRoZSBuZXh0IGZ1bmN0aW9uKHJpZ2h0KSdzIGlucHV0Lg0KYGBge3IgcGlwZSBmdW5jdGlvbn0NCjE6NSAlPiUgbWVhbigpDQojIFsxXSAzDQoxOjUgJT4lIG1lYW4oLikgJT4lIHNxcnQoKQ0KIyBbMV0gMS43MzIwNTENCg0KIyB1c2Ugb3JkZXIgZGF0YSBzZXQNCiMgMDEuIGltcG9ydCBkYXRhIGFuZCBjaGFuZ2UgdG8gdGJsIG9iamVjdA0KZGZfb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCmhlYWQoZGZfb3JkZXIsNSkNCiMgMDIuIGNoYW5nZSB0byB0Ymwgb2JqZWN0DQp0Ymxfb3JkZXIgPC0gdGJsX2RmKGRmX29yZGVyKQ0KaGVhZCh0Ymxfb3JkZXIsIDUpDQoNCiMgMDMuIG11dGF0ZSB5ZWFyIGFuZCBtb250aCBjb2x1bW4NCm1fb3JkZXIgPC0gbXV0YXRlKHRibF9vcmRlciwNCiAgICAgICAgICAgICAgICAgIG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCksDQogICAgICAgICAgICAgICAgICBvbW9udGggPSBzdWJzdHIob3JkZXJkYXRlLCA2LCA3KSkNCmhlYWQobV9vcmRlciwgNSkNCg0KIyAwNC4gZ3JvdXAgYnkgbW9udGgNCm1fb3JkZXJfbW9udGggPC0gZ3JvdXBfYnkobV9vcmRlcixvbW9udGgpDQoNCiMgMDUuIHN1bW1hcmlzZSBvcmRlciBjb3VudCBieSBtb250aA0Kc3VtbWFyaXNlKG1fb3JkZXJfbW9udGgsIG1vbnRobHlfb3JkZXJfY291bnQgPSBuKCkpDQoNCg0KIyB1c2UgcGlwZSBmdW5jdGlvbiByZXdyaXRlIGFib3ZlIGZsb3cgMDMsMDQsMDUNCnRibF9vcmRlciAlPiUNCiAgbXV0YXRlKG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCksDQogICAgICAgICBvbW9udGggPSBzdWJzdHIob3JkZXJkYXRlLCA2LCA3KSkgJT4lDQogIGdyb3VwX2J5KG9tb250aCkgJT4lDQogIHN1bW1hcmlzZShtb250aGx5X29yZGVyX2NvdW50ID0gbigpKQ0KIyBBIHRpYmJsZTogMTIgw5cgMg0KIyAgICBvbW9udGggbW9udGhseV9vcmRlcl9jb3VudA0KIyAgICAgPGNocj4gICAgICAgICAgICAgICA8aW50Pg0KIyAxICAgICAgMDEgICAgICAgICAgICAgICAxMzYwMQ0KIyAyICAgICAgMDIgICAgICAgICAgICAgICAgNjYwOQ0KIyAzICAgICAgMDMgICAgICAgICAgICAgICAgNjIzNQ0KIyA0ICAgICAgMDQgICAgICAgICAgICAgICAgNjA0Mg0KIyA1ICAgICAgMDUgICAgICAgICAgICAgICAgNTAzNw0KIyA2ICAgICAgMDYgICAgICAgICAgICAgICAgNDY5MQ0KIyA3ICAgICAgMDcgICAgICAgICAgICAgICAgNDM1NA0KIyA4ICAgICAgMDggICAgICAgICAgICAgICAgNDc2Mw0KIyA5ICAgICAgMDkgICAgICAgICAgICAgICAgNTY3Ng0KIyAxMCAgICAgMTAgICAgICAgICAgICAgICAgNzEwNg0KIyAxMSAgICAgMTEgICAgICAgICAgICAgICAxNzI2OA0KIyAxMiAgICAgMTIgICAgICAgICAgICAgICAxODYxOA0KDQpgYGANCg0KIyMgQ2hhcHRlcjExIGNvbHdpc2Xlkoxkb+WHveaVsA0K562b6YCJ6ZSA5ZSu6aKd5q+P5bm05pyA5aSn55qE6K6w5b2VDQpgYGB7ciBjb2x3aXNlIGFuZCBkbyBmdW5jdGlvbn0NCiMgTG9hZCBkcGx5ciBwYWNrYWdlDQppZighc3VwcHJlc3NXYXJuaW5ncyhyZXF1aXJlKGRwbHlyKSkpDQp7DQogICAgaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KICAgIHJlcXVpcmUoZHBseXIpDQp9DQoNCiMgaW1wb3J0IGRhdGENCm9yZGVyIDwtIHJlYWQuY3N2KCJkcGx5ci1kYXRhL29yZGVyLmNzdiIpDQoNCiMgR2V0IFllYXJseSBPcmRlciBkYXRhIGFuZCBzcGxpdCBieSB5ZWFyDQpZZWFybHlfT3JkZXIgPC0gb3JkZXIgJT4lIHNlbGVjdChvcmRlcmRhdGUsIHRvdGFscHJpY2UpICU+JQ0KICAgICAgICAgICAgICAgICAgbXV0YXRlKG95ZWFyID0gc3Vic3RyKG9yZGVyZGF0ZSwgMSwgNCkpDQoNCiMgR3JvdXAgYnkgWWVhciwgR2V0IFllYWx5IE1heGltdW4gT3JkZXINClllYWx5X01heGltdW4gPC0gWWVhcmx5X09yZGVyICU+JSBncm91cF9ieShveWVhcikgJT4lDQogICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWF4KHRvdGFscHJpY2UpKQ0KDQpgYGANCg0K562b6YCJ5q+P5bm06ZSA5ZSu6aKd5pyA5aSn55qE5Lik5p2h6K6w5b2VDQpgYGB7ciBkbyhkYXRhLCBmdW4oLikpfQ0KIyBMb2FkIGRwbHlyIHBhY2thZ2UNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUoZHBseXIpKSkNCnsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpDQogICAgcmVxdWlyZShkcGx5cikNCn0NCg0KIyBpbXBvcnQgZGF0YQ0Kb3JkZXIgPC0gcmVhZC5jc3YoImRwbHlyLWRhdGEvb3JkZXIuY3N2IikNCg0KIyBHZXQgWWVhcmx5IE9yZGVyIGRhdGEgYW5kIHNwbGl0IGJ5IHllYXINClllYXJseV9PcmRlciA8LSBvcmRlciAlPiUgc2VsZWN0KG9yZGVyZGF0ZSwgdG90YWxwcmljZSkgJT4lDQogICAgICAgICAgICAgICAgICBtdXRhdGUob3llYXIgPSBzdWJzdHIob3JkZXJkYXRlLCAxLCA0KSkNCg0KIyBHcm91cCBieSBZZWFyLCBHZXQgWWVhbHkgTWF4IDIgT3JkZXJzDQpZZWFybHlfT3JkZXIgJT4lIGdyb3VwX2J5KG95ZWFyKSAlPiUNCiAgICAgICAgYXJyYW5nZShkZXNjKHRvdGFscHJpY2UpKSAlPiUNCiAgICAgICAgZG8oLiwgaGVhZCguLCAyKSkNCiMgU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFsxMiB4IDNdDQojIEdyb3Vwczogb3llYXIgWzZdDQojDQojICAgICBvcmRlcmRhdGUgdG90YWxwcmljZSBveWVhcg0KIyAgICAgICAgPGZjdHI+ICAgICAgPGRibD4gPGNocj4NCiMgMSAgMjAwOS0xMi0xNyAgICAyMjQ0LjAwICAyMDA5DQojIDIgIDIwMDktMTAtMjYgICAgMTE1NC42NSAgMjAwOQ0KIyAzICAyMDEwLTA5LTA1ICAgIDIyNTAuMDAgIDIwMTANCiMgNCAgMjAxMC0xMC0wNiAgICAyMjUwLjAwICAyMDEwDQojIDUgIDIwMTEtMDUtMDkgICAgMjI1MC4wMCAgMjAxMQ0KIyA2ICAyMDExLTA1LTE3ICAgIDIwMDAuMDAgIDIwMTENCiMgNyAgMjAxMi0xMi0xMiAgICA2NzgwLjAwICAyMDEyDQojIDggIDIwMTItMTEtMTIgICAgNjYwNi4wMCAgMjAxMg0KIyA5ICAyMDEzLTAxLTE4ICAgIDQwNTAuMDAgIDIwMTMNCiMgMTAgMjAxMy0wNi0yNiAgICAzNTkyLjAwICAyMDEzDQojIDExIDIwMTQtMDMtMjkgICAgNDczNS4wMCAgMjAxNA0KIyAxMiAyMDE0LTAzLTMwICAgIDQzNzguNTAgIDIwMTQNCg0KYGBgDQoNCiMjIyBwbHlyIHBhY2thZ2UgY29sd2lzZSBmdW5jdGlvbg0KYGBge3IgY29sd2lzZSBmdW5jdGlvbn0NCiMgTG9hZCBwbHlyIHBhY2thZ2UNCmlmKCFzdXBwcmVzc1dhcm5pbmdzKHJlcXVpcmUocGx5cikpKQ0Kew0KICAgIGluc3RhbGwucGFja2FnZXMoJ3BseXInKQ0KICAgIHJlcXVpcmUocGx5cikNCn0NCg0KIyBsb2FkIGFuZCBjaGVjayBpcmlzIGRhdGEgc2V0DQpoZWFkKGlyaXMsIDUpDQoNCiMgdG8gcm91bmQgZXZlcnkgY29sdW1uIHVzZSBjb2x3aXNlIGZ1bmN0aW9uDQojIGNhbGwgZnVuY3Rpb24gdG8gZWFjaCBjb2x1bW4NCiMgY29sd2lzZShmdW5jdGlvbikoZGF0YS5mcmFtZSkNCmNvbHdpc2Uocm91bmQpKGlyaXNbLCAxOjRdKSAlPiUgaGVhZCguLCA1KQ0KIyAgIFNlcGFsLkxlbmd0aCBTZXBhbC5XaWR0aCBQZXRhbC5MZW5ndGggUGV0YWwuV2lkdGgNCiMgMSAgICAgICAgICAgIDUgICAgICAgICAgIDQgICAgICAgICAgICAxICAgICAgICAgICAwDQojIDIgICAgICAgICAgICA1ICAgICAgICAgICAzICAgICAgICAgICAgMSAgICAgICAgICAgMA0KIyAzICAgICAgICAgICAgNSAgICAgICAgICAgMyAgICAgICAgICAgIDEgICAgICAgICAgIDANCiMgNCAgICAgICAgICAgIDUgICAgICAgICAgIDMgICAgICAgICAgICAyICAgICAgICAgICAwDQojIDUgICAgICAgICAgICA1ICAgICAgICAgICA0ICAgICAgICAgICAgMSAgICAgICAgICAgMA0KDQpgYGANCg0KIyMgQ2hhcHRlcjEyIOi/nuaOpU15U1FM5pWw5o2u5bqTDQrov57mjqVNeVNRTOaVsOaNruW6kw0KYGBge3IgY29ubmVjdCBteXNxbH0NCiMgbXlzcWwgZGF0YSBiYXNlDQpzcmNfZGF0YWJhc2UgPC0gc3JjX215c3FsKGRibmFtZSA9ICJzcWxib29rIiwgaG9zdCA9ICIxMjcuMC4wLjEiLCBwb3J0ID0gIjMwNjMiLHVzZXIgPSAicm9vdCIscGFzc3dvcmQgPSAicm9vdCIpDQoNCiMgbXlzcWwgdGFibGUNCnNyY190YWJsZSA8LSB0Ymwoc3JjX2RhdGFiYXNlLCBmcm9tID0gIm9yZGVycyIpDQoNCiMgZXhlY3V0ZSBzcWwgY29tbWFuZA0Kc3FsUXVlcnlSZXN1bHRzIDwtIHNlbGVjdChzcmNfdGFibGUsIG9yZGVyaWQsIG9yZGVyZGF0ZSkNCiMgb3IgdXNlIHBpcGUgZnVuY3Rpb24NCnNxbFF1ZXJ5UmVzdWx0cyA8LSBzcmNfdGFibGUgJT4lIHNlbGVjdChvcmRlcmlkLCBvcmRlcmRhdGUpDQoNCiMgY2hlY2sgc3FsIHF1ZXJ5IGNvbW1hbmQNCnNxbFF1ZXJ5UmVzdWx0cyRxdWVyeQ0KDQojIHNhdmUgcmVzdWx0cyBhcyBjc3YgZmlsZQ0Kd3JpdGUuY3N2KHNxbFF1ZXJ5UmVzdWx0cywgImRwbHlyLWRhdGEvb3JkZXJfcmVjb3JkLmNzdiIpDQoNCiMgc2hvdyBzcWxRdWVyeVJlc3VsdHMNCnNxbFF1ZXJ5UmVzdWx0cw0KDQojIG15c3FsIGRhdGEgYmFzZQ0KIyBteXNxbCAtdSByb290IC1wDQojIGVudGVyIHBhc3N3b3JkDQoNCiMgc2hvdyBkYXRhYmFzZXMNCiMgc2hvdyBkYXRhYmFzZXMNCg0KI3VzZSB3aGljaCBkYXRhYmFzZSwgY2hhbmdlIHRvIHlvdXIgZGF0YWJhc2UNCiMgdXNlIG15ZGF0YWJhc2UNCg0KIyBzaG93IHRhYmxlcyBpbiB5b3VyIGRhdGFiYXNlDQojIHNob3cgdGFibGVzDQoNCmBgYA0KDQojIyBDaGFwdGVyMTMgRXhhbXBsZSBkcGx5ciBhbmQgcGlwZWxpbmUgb3BlcmF0b3INCg0KPiBbZHBseXIgRXhhbXBsZXMgd2l0aCBwaXBlbGluZV0oaHR0cHM6Ly9yZW5rdW4ubWUvcGlwZVItdHV0b3JpYWwvRXhhbXBsZXMvZHBseXIuaHRtbCkNCg0KPiBbcmxpc3QgRXhhbXBsZXMgd2l0aCBwaXBlbGluZV0oaHR0cHM6Ly9yZW5rdW4ubWUvcGlwZVItdHV0b3JpYWwvRXhhbXBsZXMvcmxpc3QuaHRtbCkNCg0KDQpgaGZsaWdodHNgIGlzIGEgZGF0YXNldCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCBmbGlnaHRzIHRoYXQgZGVwYXJ0ZWQgSG91c3RvbiBpbiAyMDExLiBJbiB0aGUgZGVzY3JpcHRpb24gdGhlIGF1dGhvciB3cml0ZXM6DQoNCj4gVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGFsbCBmbGlnaHRzIGRlcGFydGluZyBmcm9tIEhvdXN0b24gYWlycG9ydHMgSUFIIChHZW9yZ2UgQnVzaCBJbnRlcmNvbnRpbmVudGFsKSBhbmQgSE9VIChIb3VzdG9uIEhvYmJ5KS4gVGhlIGRhdGEgY29tZXMgZnJvbSB0aGUgUmVzZWFyY2ggYW5kIElubm92YXRpb24gVGVjaG5vbG9neSBBZG1pbmlzdHJhdGlvbiBhdCB0aGUgQnVyZWF1IG9mIFRyYW5zcG9yYXRpb24gc3RhdGlzdGljczogW2h0dHA6Ly93d3cudHJhbnN0YXRzLmJ0cy5nb3YvRGF0YWJhc2VJbmZvLmFzcD9EQl9JRD0xMjAmTGluaz0wXShodHRwOi8vd3d3LnRyYW5zdGF0cy5idHMuZ292L0RhdGFiYXNlSW5mby5hc3A/REJfSUQ9MTIwJkxpbms9MCkNCg0KSGF2aW5nIGtub3duIHdoYXQgdGhlIGRhdGEgaXMgYWxsIGFib3V0LCB0aGVuIHdlIGxvYWQgdGhlIGxpYnJhcmllcyBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKGMoImRwbHlyIiwiaGZsaWdodHMiKSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBpcGVSKQ0KIyBvciB1c2UNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KGhmbGlnaHRzKSAjIGluc3RhbGwucGFja2FnZXMoImhmbGlnaHRzIikNCmRhdGEoaGZsaWdodHMpDQoNCnN0cihoZmxpZ2h0cykNCiMgJ2RhdGEuZnJhbWUnOgkyMjc0OTYgb2JzLiBvZiAgMjEgdmFyaWFibGVzOg0KIyAgJCBZZWFyICAgICAgICAgICAgIDogaW50ICAyMDExIDIwMTEgMjAxMSAyMDExIDIwMTEgMjAxMSAyMDExIDIwMTEgMjAxMSAyMDExIC4uLg0KIyAgJCBNb250aCAgICAgICAgICAgIDogaW50ICAxIDEgMSAxIDEgMSAxIDEgMSAxIC4uLg0KIyAgJCBEYXlvZk1vbnRoICAgICAgIDogaW50ICAxIDIgMyA0IDUgNiA3IDggOSAxMCAuLi4NCiMgICQgRGF5T2ZXZWVrICAgICAgICA6IGludCAgNiA3IDEgMiAzIDQgNSA2IDcgMSAuLi4NCiMgICQgRGVwVGltZSAgICAgICAgICA6IGludCAgMTQwMCAxNDAxIDEzNTIgMTQwMyAxNDA1IDEzNTkgMTM1OSAxMzU1IDE0NDMgMTQ0MyAuLi4NCiMgICQgQXJyVGltZSAgICAgICAgICA6IGludCAgMTUwMCAxNTAxIDE1MDIgMTUxMyAxNTA3IDE1MDMgMTUwOSAxNDU0IDE1NTQgMTU1MyAuLi4NCiMgICQgVW5pcXVlQ2FycmllciAgICA6IGNociAgIkFBIiAiQUEiICJBQSIgIkFBIiAuLi4NCiMgICQgRmxpZ2h0TnVtICAgICAgICA6IGludCAgNDI4IDQyOCA0MjggNDI4IDQyOCA0MjggNDI4IDQyOCA0MjggNDI4IC4uLg0KIyAgJCBUYWlsTnVtICAgICAgICAgIDogY2hyICAiTjU3NkFBIiAiTjU1N0FBIiAiTjU0MUFBIiAiTjQwM0FBIiAuLi4NCiMgICQgQWN0dWFsRWxhcHNlZFRpbWU6IGludCAgNjAgNjAgNzAgNzAgNjIgNjQgNzAgNTkgNzEgNzAgLi4uDQojICAkIEFpclRpbWUgICAgICAgICAgOiBpbnQgIDQwIDQ1IDQ4IDM5IDQ0IDQ1IDQzIDQwIDQxIDQ1IC4uLg0KIyAgJCBBcnJEZWxheSAgICAgICAgIDogaW50ICAtMTAgLTkgLTggMyAtMyAtNyAtMSAtMTYgNDQgNDMgLi4uDQojICAkIERlcERlbGF5ICAgICAgICAgOiBpbnQgIDAgMSAtOCAzIDUgLTEgLTEgLTUgNDMgNDMgLi4uDQojICAkIE9yaWdpbiAgICAgICAgICAgOiBjaHIgICJJQUgiICJJQUgiICJJQUgiICJJQUgiIC4uLg0KIyAgJCBEZXN0ICAgICAgICAgICAgIDogY2hyICAiREZXIiAiREZXIiAiREZXIiAiREZXIiAuLi4NCiMgICQgRGlzdGFuY2UgICAgICAgICA6IGludCAgMjI0IDIyNCAyMjQgMjI0IDIyNCAyMjQgMjI0IDIyNCAyMjQgMjI0IC4uLg0KIyAgJCBUYXhpSW4gICAgICAgICAgIDogaW50ICA3IDYgNSA5IDkgNiAxMiA3IDggNiAuLi4NCiMgICQgVGF4aU91dCAgICAgICAgICA6IGludCAgMTMgOSAxNyAyMiA5IDEzIDE1IDEyIDIyIDE5IC4uLg0KIyAgJCBDYW5jZWxsZWQgICAgICAgIDogaW50ICAwIDAgMCAwIDAgMCAwIDAgMCAwIC4uLg0KIyAgJCBDYW5jZWxsYXRpb25Db2RlIDogY2hyICAiIiAiIiAiIiAiIiAuLi4NCiMgICQgRGl2ZXJ0ZWQgICAgICAgICA6IGludCAgMCAwIDAgMCAwIDAgMCAwIDAgMCAuLi4NCmBgYA0KDQpUaGUgZGF0YSBpcyB0YWJ1bGFyIGFuZCB2ZXJ5IHdlbGwgZml0IGluIGEgZGF0YSBmcmFtZS4gUmVtYXJrYWJseSBpdCBoYXMgMjI3NDk2IHJvd3Mgd2hpY2ggaXMgbXVjaCBsYXJnZXIgdGhhbiBzbWFsbCBkYXRhc2V0cyBsaWtlIG10Y2Fycy4NCg0KVHdvIGNvbHVtbnMgaW4gdGhlIGRhdGEgZnJhbWUgYXR0cmFjdHMgb3VyIGF0dGVudGlvbjogYERpc3RhbmNlYCBhbmQgYEFjdHVhbEVsYXBzZWRUaW1lYC4gSWYgd2UgZGl2aWRlIERpc3RhbmNlIGJ5IEFjdHVhbEVsYXBzZWRUaW1lIHdlIGNhbiBnZXQgdGhlIGFjdHVhbCBmbGlnaHQgc3BlZWQuIFRoZXJlZm9yZSwgaW4gdGhpcyBleGFtcGxlLCB3ZSB1c2UgZHBseXIgZnVuY3Rpb25zIHRvIHRyYW5zZm9ybSB0aGUgZGF0YSBpbiBwaXBlbGluZSBhbmQgc2VlIHdoaWNoIGNhcnJpZXIgaGFzIGZhc3RlciBmbGlnaHRzLg0KDQpgYGB7cn0NCmhmbGlnaHRzICU+JSANCiAgIyAxLiBmaWx0ZXIgb3V0IG5vIGNhbmNlbGQgZmxpZ2h0DQogIGZpbHRlcihDYW5jZWxsZWQgPT0gMCkgJT4lDQogICMgMi4gbXV0YXRlIG5ldyBjb2x1bW4gc3BlZWQNCiAgbXV0YXRlKHNwZWVkID0gRGlzdGFuY2UgLyBBY3R1YWxFbGFwc2VkVGltZSkgJT4lDQogICMgMy4gc2F2ZSB0byBoZmxpZ2h0czINCiAgKH4gaGZsaWdodHMyKSAlPiUgDQogICMgNC4gZ3JvdXBfYnkgVW5pcXVlQ2Fycmllcg0KICAgIGdyb3VwX2J5KFVuaXF1ZUNhcnJpZXIpICU+JQ0KICAgICNncm91cF9ieSguZGF0YSA9IC4sVW5pcXVlQ2FycmllcikgICU+JQ0KICAjIDUuIHN1bW1hcml6ZQ0KICBzdW1tYXJpemUobWVhbl9zcGVlZCA9IG1lYW4oc3BlZWQsbmEucm0gPSBUUlVFKSkgJT4lDQogICMgNi4gYXJyYW5nZSwgYnkgc3BlZWQgZGVzYw0KICBhcnJhbmdlKGRlc2MobWVhbl9zcGVlZCkpICU+JQ0KICAjIDcuIGJhcnBsb3QsIHdoeSB3aXRoPw0KICB3aXRoKGJhcnBsb3QobWVhbl9zcGVlZCxuYW1lcy5hcmcgPSBVbmlxdWVDYXJyaWVyLA0KICAgIG1haW4gPSAiQXZlcmFnZSBmbGlnaHQgc3BlZWQiKSkNCmBgYA0KDQoNCg0KDQojIyBFbmQgMjAxNy0wNi0xMCBCeSBTdG9uZS5Ib3UNCg0KVXBkYXRlZCBpbiAyMDE3MDcwMiwgYWRkIGV4YW1wbGUNCg==